classlib: improve accuracy of Double.toString

This commit is contained in:
Alexey Andreev 2023-09-14 20:55:09 +02:00
parent 7059038cf0
commit e1706f242d
2 changed files with 49 additions and 6 deletions

View File

@ -47,7 +47,7 @@ public final class DoubleAnalyzer {
mantissa |= 1L << 52;
}
int decExponent = Arrays.binarySearch(exp10Table, exponent);
int decExponent = Arrays.binarySearch(exp10Table, (short) exponent);
if (decExponent < 0) {
decExponent = -decExponent;
}
@ -810,7 +810,7 @@ public final class DoubleAnalyzer {
-1468012460592228864L,
};
private static int[] exp10Table = {
static short[] exp10Table = {
-70,
-66,
-63,

View File

@ -26,7 +26,7 @@ public final class DoubleSynthesizer {
}
var binMantissa = DoubleAnalyzer.mulAndShiftRight(mantissa, mantissa10Table[indexInTable], 0);
var binExp = exp10Table[indexInTable];
int binExp = exp10Table[indexInTable];
var binMantissaShift = (64 - Long.numberOfLeadingZeros(binMantissa)) - 58;
if (binMantissaShift >= 0) {
@ -39,7 +39,27 @@ public final class DoubleSynthesizer {
if (binExp >= 2047) {
return negative ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
}
binMantissa += 1L << 4;
var mantissaLowerBits = 5;
var mantissaLowerPos = 1 << mantissaLowerBits;
var error = (int) (binMantissa & (mantissaLowerPos - 1));
var correction = mantissaLowerPos >> 1;
if (Math.abs(error - (mantissaLowerPos >>> 1)) <= 1) {
var binMantissaWithoutError = binMantissa & -mantissaLowerPos;
var low = calcDecMantissa(binMantissaWithoutError, mantissaLowerPos, indexInTable, binExp);
var hi = calcDecMantissa(binMantissaWithoutError + mantissaLowerPos, mantissaLowerPos,
indexInTable, binExp);
low = mantissa - low;
hi = hi - mantissa;
var cmp = Long.compareUnsigned(low, hi);
if (cmp < 0) {
correction = -error;
} else if (cmp > 0) {
correction = mantissaLowerPos - error;
}
}
binMantissa += correction;
if ((binMantissa & (-1L << 58L)) != 0) {
binMantissa >>>= 1;
binExp++;
@ -49,7 +69,7 @@ public final class DoubleSynthesizer {
binExp = 0;
}
binMantissa = (binMantissa >>> 5) & (-1L << 12 >>> 12);
binMantissa = (binMantissa >>> mantissaLowerBits) & (-1L << 12 >>> 12);
var iee754 = binMantissa | ((long) binExp << 52);
if (negative) {
iee754 ^= 1L << 63;
@ -57,6 +77,29 @@ public final class DoubleSynthesizer {
return Double.longBitsToDouble(iee754);
}
private static long calcDecMantissa(long mantissa, int lowerBit, int indexInTable, int binExp) {
var half = lowerBit >>> 1;
var shift = 7 - (DoubleAnalyzer.exp10Table[indexInTable] - binExp);
var decMantissa = DoubleAnalyzer.mulAndShiftRight(mantissa,
DoubleAnalyzer.mantissa10Table[indexInTable], shift);
var decMantissaHi = DoubleAnalyzer.mulAndShiftRight(mantissa + half,
DoubleAnalyzer.mantissa10Table[indexInTable], shift);
var decMantissaLow = DoubleAnalyzer.mulAndShiftRight(mantissa - half,
DoubleAnalyzer.mantissa10Table[indexInTable], shift);
var lowerPos = DoubleAnalyzer.findLowerDistance(decMantissa, decMantissaLow);
var upperPos = DoubleAnalyzer.findUpperDistance(decMantissa, decMantissaHi);
var posCmp = Long.compareUnsigned(lowerPos, upperPos);
if (posCmp > 0) {
decMantissa = Long.divideUnsigned(decMantissa, lowerPos) * lowerPos;
} else if (posCmp < 0) {
decMantissa = Long.divideUnsigned(decMantissa, upperPos) * upperPos + upperPos;
} else {
decMantissa = Long.divideUnsigned(decMantissa + (upperPos / 2), upperPos) * upperPos;
}
return decMantissa;
}
// Numbers in the table below are generated by DoubleSynthesizerGenerator
private static final long[] mantissa10Table = {
@ -722,7 +765,7 @@ public final class DoubleSynthesizer {
-8425902273664687726L,
};
private static int[] exp10Table = {
private static short[] exp10Table = {
-76,
-72,
-69,