FloatToDecimalTest.java
package com.fasterxml.jackson.core.io.schubfach;
import java.util.Random;
import org.junit.jupiter.api.Test;
import static com.fasterxml.jackson.core.io.schubfach.FloatToDecimalChecker.*;
import static java.lang.Float.intBitsToFloat;
import static java.lang.StrictMath.scalb;
import static org.junit.jupiter.api.Assertions.assertEquals;
class FloatToDecimalTest {
/*
MIN_NORMAL is incorrectly rendered by the JDK.
*/
@Test
void extremeValues() {
toDec(Float.NEGATIVE_INFINITY);
toDec(-Float.MAX_VALUE);
toDec(-Float.MIN_NORMAL);
toDec(-Float.MIN_VALUE);
toDec(-0.0f);
toDec(0.0f);
toDec(Float.MIN_VALUE);
toDec(Float.MIN_NORMAL);
toDec(Float.MAX_VALUE);
toDec(Float.POSITIVE_INFINITY);
toDec(Float.NaN);
/*
Quiet NaNs have the most significant bit of the mantissa as 1,
while signaling NaNs have it as 0.
Exercise 4 combinations of quiet/signaling NaNs and
"positive/negative" NaNs.
*/
toDec(intBitsToFloat(0x7FC0_0001));
toDec(intBitsToFloat(0x7F80_0001));
toDec(intBitsToFloat(0xFFC0_0001));
toDec(intBitsToFloat(0xFF80_0001));
/*
All values treated specially by Schubfach
*/
for (int c = 1; c < C_TINY; ++c) {
toDec(c * Float.MIN_VALUE);
}
}
/*
Some "powers of 10" are incorrectly rendered by the JDK.
The rendering is either too long or it is not the closest decimal.
*/
@Test
void powersOf10() {
for (int e = E_MIN; e <= E_MAX; ++e) {
toDec(Float.parseFloat("1e" + e));
}
}
/*
Many powers of 2 are incorrectly rendered by the JDK.
The rendering is either too long or it is not the closest decimal.
*/
@Test
void powersOf2() {
for (float v = Float.MIN_VALUE; v <= Float.MAX_VALUE; v *= 2) {
toDec(v);
}
}
@Test
void constants() {
assertEquals(FloatToDecimal.P, P, "P");
assertEquals(C_MIN, (long) (float) C_MIN, "C_MIN");
assertEquals(C_MAX, (long) (float) C_MAX, "C_MAX");
assertEquals(Float.MIN_VALUE, MIN_VALUE, "MIN_VALUE");
assertEquals(Float.MIN_NORMAL, MIN_NORMAL, "MIN_NORMAL");
assertEquals(Float.MAX_VALUE, MAX_VALUE, "MAX_VALUE");
assertEquals(FloatToDecimal.Q_MIN, Q_MIN, "Q_MIN");
assertEquals(FloatToDecimal.Q_MAX, Q_MAX, "Q_MAX");
assertEquals(FloatToDecimal.K_MIN, K_MIN, "K_MIN");
assertEquals(FloatToDecimal.K_MAX, K_MAX, "K_MAX");
assertEquals(FloatToDecimal.H, H, "H");
assertEquals(FloatToDecimal.E_MIN, E_MIN, "E_MIN");
assertEquals(FloatToDecimal.E_MAX, E_MAX, "E_MAX");
assertEquals(FloatToDecimal.C_TINY, C_TINY, "C_TINY");
}
@Test
void someAnomalies() {
for (String dec : Anomalies) {
toDec(Float.parseFloat(dec));
}
}
@Test
void paxson() {
for (int i = 0; i < PaxsonSignificands.length; ++i) {
toDec(scalb(PaxsonSignificands[i], PaxsonExponents[i]));
}
}
/*
Tests all positive integers below 2^23.
These are all exact floats and exercise the fast path.
*/
@Test
void ints() {
// 29-Nov-2022, tatu: Reduce from original due to slowness
// for (int i = 1; i < 1 << P - 1; ++i) {
for (int i = 1; i < 1 << P - 1; i += 3) {
toDec(i);
}
}
@Test
void randomNumberTests() {
FloatToDecimalChecker.randomNumberTests(1_000_000, new Random());
}
}