|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package jdk.internal.math; |
|
|
|
import java.util.Arrays; |
|
import java.util.regex.*; |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public class FloatingDecimal{ |
|
// |
|
// Constants of the implementation; |
|
// most are IEEE-754 related. |
|
// (There are more really boring constants at the end.) |
|
|
|
static final int EXP_SHIFT = DoubleConsts.SIGNIFICAND_WIDTH - 1; |
|
static final long FRACT_HOB = ( 1L<<EXP_SHIFT ); |
|
static final long EXP_ONE = ((long)DoubleConsts.EXP_BIAS)<<EXP_SHIFT; |
|
static final int MAX_SMALL_BIN_EXP = 62; |
|
static final int MIN_SMALL_BIN_EXP = -( 63 / 3 ); |
|
static final int MAX_DECIMAL_DIGITS = 15; |
|
static final int MAX_DECIMAL_EXPONENT = 308; |
|
static final int MIN_DECIMAL_EXPONENT = -324; |
|
static final int BIG_DECIMAL_EXPONENT = 324; |
|
static final int MAX_NDIGITS = 1100; |
|
|
|
static final int SINGLE_EXP_SHIFT = FloatConsts.SIGNIFICAND_WIDTH - 1; |
|
static final int SINGLE_FRACT_HOB = 1<<SINGLE_EXP_SHIFT; |
|
static final int SINGLE_MAX_DECIMAL_DIGITS = 7; |
|
static final int SINGLE_MAX_DECIMAL_EXPONENT = 38; |
|
static final int SINGLE_MIN_DECIMAL_EXPONENT = -45; |
|
static final int SINGLE_MAX_NDIGITS = 200; |
|
|
|
static final int INT_DECIMAL_DIGITS = 9; |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static String toJavaFormatString(double d) { |
|
return getBinaryToASCIIConverter(d).toJavaFormatString(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static String toJavaFormatString(float f) { |
|
return getBinaryToASCIIConverter(f).toJavaFormatString(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static void appendTo(double d, Appendable buf) { |
|
getBinaryToASCIIConverter(d).appendTo(buf); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static void appendTo(float f, Appendable buf) { |
|
getBinaryToASCIIConverter(f).appendTo(buf); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static double parseDouble(String s) throws NumberFormatException { |
|
return readJavaFormatString(s).doubleValue(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static float parseFloat(String s) throws NumberFormatException { |
|
return readJavaFormatString(s).floatValue(); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public interface BinaryToASCIIConverter { |
|
|
|
|
|
|
|
*/ |
|
public String toJavaFormatString(); |
|
|
|
|
|
|
|
|
|
*/ |
|
public void appendTo(Appendable buf); |
|
|
|
|
|
|
|
|
|
*/ |
|
public int getDecimalExponent(); |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public int getDigits(char[] digits); |
|
|
|
|
|
|
|
|
|
*/ |
|
public boolean isNegative(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public boolean isExceptional(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public boolean digitsRoundedUp(); |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public boolean decimalDigitsExact(); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
private static class ExceptionalBinaryToASCIIBuffer implements BinaryToASCIIConverter { |
|
private final String image; |
|
private boolean isNegative; |
|
|
|
public ExceptionalBinaryToASCIIBuffer(String image, boolean isNegative) { |
|
this.image = image; |
|
this.isNegative = isNegative; |
|
} |
|
|
|
@Override |
|
public String toJavaFormatString() { |
|
return image; |
|
} |
|
|
|
@Override |
|
public void appendTo(Appendable buf) { |
|
if (buf instanceof StringBuilder) { |
|
((StringBuilder) buf).append(image); |
|
} else if (buf instanceof StringBuffer) { |
|
((StringBuffer) buf).append(image); |
|
} else { |
|
assert false; |
|
} |
|
} |
|
|
|
@Override |
|
public int getDecimalExponent() { |
|
throw new IllegalArgumentException("Exceptional value does not have an exponent"); |
|
} |
|
|
|
@Override |
|
public int getDigits(char[] digits) { |
|
throw new IllegalArgumentException("Exceptional value does not have digits"); |
|
} |
|
|
|
@Override |
|
public boolean isNegative() { |
|
return isNegative; |
|
} |
|
|
|
@Override |
|
public boolean isExceptional() { |
|
return true; |
|
} |
|
|
|
@Override |
|
public boolean digitsRoundedUp() { |
|
throw new IllegalArgumentException("Exceptional value is not rounded"); |
|
} |
|
|
|
@Override |
|
public boolean decimalDigitsExact() { |
|
throw new IllegalArgumentException("Exceptional value is not exact"); |
|
} |
|
} |
|
|
|
private static final String INFINITY_REP = "Infinity"; |
|
private static final int INFINITY_LENGTH = INFINITY_REP.length(); |
|
private static final String NAN_REP = "NaN"; |
|
private static final int NAN_LENGTH = NAN_REP.length(); |
|
|
|
private static final BinaryToASCIIConverter B2AC_POSITIVE_INFINITY = new ExceptionalBinaryToASCIIBuffer(INFINITY_REP, false); |
|
private static final BinaryToASCIIConverter B2AC_NEGATIVE_INFINITY = new ExceptionalBinaryToASCIIBuffer("-" + INFINITY_REP, true); |
|
private static final BinaryToASCIIConverter B2AC_NOT_A_NUMBER = new ExceptionalBinaryToASCIIBuffer(NAN_REP, false); |
|
private static final BinaryToASCIIConverter B2AC_POSITIVE_ZERO = new BinaryToASCIIBuffer(false, new char[]{'0'}); |
|
private static final BinaryToASCIIConverter B2AC_NEGATIVE_ZERO = new BinaryToASCIIBuffer(true, new char[]{'0'}); |
|
|
|
|
|
|
|
*/ |
|
static class BinaryToASCIIBuffer implements BinaryToASCIIConverter { |
|
private boolean isNegative; |
|
private int decExponent; |
|
private int firstDigitIndex; |
|
private int nDigits; |
|
private final char[] digits; |
|
private final char[] buffer = new char[26]; |
|
|
|
// |
|
// The fields below provide additional information about the result of |
|
// the binary to decimal digits conversion done in dtoa() and roundup() |
|
// methods. They are changed if needed by those two methods. |
|
// |
|
|
|
|
|
private boolean exactDecimalConversion = false; |
|
|
|
// True if the result of the binary to decimal conversion was rounded-up |
|
|
|
private boolean decimalDigitsRoundedUp = false; |
|
|
|
|
|
|
|
|
|
*/ |
|
BinaryToASCIIBuffer(){ |
|
this.digits = new char[20]; |
|
} |
|
|
|
|
|
|
|
*/ |
|
BinaryToASCIIBuffer(boolean isNegative, char[] digits){ |
|
this.isNegative = isNegative; |
|
this.decExponent = 0; |
|
this.digits = digits; |
|
this.firstDigitIndex = 0; |
|
this.nDigits = digits.length; |
|
} |
|
|
|
@Override |
|
public String toJavaFormatString() { |
|
int len = getChars(buffer); |
|
return new String(buffer, 0, len); |
|
} |
|
|
|
@Override |
|
public void appendTo(Appendable buf) { |
|
int len = getChars(buffer); |
|
if (buf instanceof StringBuilder) { |
|
((StringBuilder) buf).append(buffer, 0, len); |
|
} else if (buf instanceof StringBuffer) { |
|
((StringBuffer) buf).append(buffer, 0, len); |
|
} else { |
|
assert false; |
|
} |
|
} |
|
|
|
@Override |
|
public int getDecimalExponent() { |
|
return decExponent; |
|
} |
|
|
|
@Override |
|
public int getDigits(char[] digits) { |
|
System.arraycopy(this.digits,firstDigitIndex,digits,0,this.nDigits); |
|
return this.nDigits; |
|
} |
|
|
|
@Override |
|
public boolean isNegative() { |
|
return isNegative; |
|
} |
|
|
|
@Override |
|
public boolean isExceptional() { |
|
return false; |
|
} |
|
|
|
@Override |
|
public boolean digitsRoundedUp() { |
|
return decimalDigitsRoundedUp; |
|
} |
|
|
|
@Override |
|
public boolean decimalDigitsExact() { |
|
return exactDecimalConversion; |
|
} |
|
|
|
private void setSign(boolean isNegative) { |
|
this.isNegative = isNegative; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private void developLongDigits( int decExponent, long lvalue, int insignificantDigits ){ |
|
if ( insignificantDigits != 0 ){ |
|
// Discard non-significant low-order bits, while rounding, |
|
// up to insignificant value. |
|
long pow10 = FDBigInteger.LONG_5_POW[insignificantDigits] << insignificantDigits; |
|
long residue = lvalue % pow10; |
|
lvalue /= pow10; |
|
decExponent += insignificantDigits; |
|
if ( residue >= (pow10>>1) ){ |
|
|
|
lvalue++; |
|
} |
|
} |
|
int digitno = digits.length -1; |
|
int c; |
|
if ( lvalue <= Integer.MAX_VALUE ){ |
|
assert lvalue > 0L : lvalue; |
|
// even easier subcase! |
|
|
|
int ivalue = (int)lvalue; |
|
c = ivalue%10; |
|
ivalue /= 10; |
|
while ( c == 0 ){ |
|
decExponent++; |
|
c = ivalue%10; |
|
ivalue /= 10; |
|
} |
|
while ( ivalue != 0){ |
|
digits[digitno--] = (char)(c+'0'); |
|
decExponent++; |
|
c = ivalue%10; |
|
ivalue /= 10; |
|
} |
|
digits[digitno] = (char)(c+'0'); |
|
} else { |
|
// same algorithm as above (same bugs, too ) |
|
|
|
c = (int)(lvalue%10L); |
|
lvalue /= 10L; |
|
while ( c == 0 ){ |
|
decExponent++; |
|
c = (int)(lvalue%10L); |
|
lvalue /= 10L; |
|
} |
|
while ( lvalue != 0L ){ |
|
digits[digitno--] = (char)(c+'0'); |
|
decExponent++; |
|
c = (int)(lvalue%10L); |
|
lvalue /= 10; |
|
} |
|
digits[digitno] = (char)(c+'0'); |
|
} |
|
this.decExponent = decExponent+1; |
|
this.firstDigitIndex = digitno; |
|
this.nDigits = this.digits.length - digitno; |
|
} |
|
|
|
private void dtoa( int binExp, long fractBits, int nSignificantBits, boolean isCompatibleFormat) |
|
{ |
|
assert fractBits > 0 ; |
|
assert (fractBits & FRACT_HOB)!=0 ; |
|
// Examine number. Determine if it is an easy case, |
|
// which we can do pretty trivially using float/long conversion, |
|
|
|
final int tailZeros = Long.numberOfTrailingZeros(fractBits); |
|
|
|
|
|
final int nFractBits = EXP_SHIFT+1-tailZeros; |
|
|
|
// reset flags to default values as dtoa() does not always set these |
|
// flags and a prior call to dtoa() might have set them to incorrect |
|
|
|
decimalDigitsRoundedUp = false; |
|
exactDecimalConversion = false; |
|
|
|
|
|
int nTinyBits = Math.max( 0, nFractBits - binExp - 1 ); |
|
if ( binExp <= MAX_SMALL_BIN_EXP && binExp >= MIN_SMALL_BIN_EXP ){ |
|
// Look more closely at the number to decide if, |
|
// with scaling by 10^nTinyBits, the result will fit in |
|
|
|
if ( (nTinyBits < FDBigInteger.LONG_5_POW.length) && ((nFractBits + N_5_BITS[nTinyBits]) < 64 ) ){ |
|
// |
|
// We can do this: |
|
// take the fraction bits, which are normalized. |
|
// (a) nTinyBits == 0: Shift left or right appropriately |
|
// to align the binary point at the extreme right, i.e. |
|
// where a long int point is expected to be. The integer |
|
// result is easily converted to a string. |
|
// (b) nTinyBits > 0: Shift right by EXP_SHIFT-nFractBits, |
|
// which effectively converts to long and scales by |
|
// 2^nTinyBits. Then multiply by 5^nTinyBits to |
|
// complete the scaling. We know this won't overflow |
|
// because we just counted the number of bits necessary |
|
// in the result. The integer you get from this can |
|
// then be converted to a string pretty easily. |
|
|
|
if ( nTinyBits == 0 ) { |
|
int insignificant; |
|
if ( binExp > nSignificantBits ){ |
|
insignificant = insignificantDigitsForPow2(binExp-nSignificantBits-1); |
|
} else { |
|
insignificant = 0; |
|
} |
|
if ( binExp >= EXP_SHIFT ){ |
|
fractBits <<= (binExp-EXP_SHIFT); |
|
} else { |
|
fractBits >>>= (EXP_SHIFT-binExp) ; |
|
} |
|
developLongDigits( 0, fractBits, insignificant ); |
|
return; |
|
} |
|
// |
|
// The following causes excess digits to be printed |
|
// out in the single-float case. Our manipulation of |
|
// halfULP here is apparently not correct. If we |
|
// better understand how this works, perhaps we can |
|
// use this special case again. But for the time being, |
|
// we do not. |
|
// else { |
|
// fractBits >>>= EXP_SHIFT+1-nFractBits; |
|
// fractBits//= long5pow[ nTinyBits ]; |
|
// halfULP = long5pow[ nTinyBits ] >> (1+nSignificantBits-nFractBits); |
|
// developLongDigits( -nTinyBits, fractBits, insignificantDigits(halfULP) ); |
|
// return; |
|
// } |
|
// |
|
} |
|
} |
|
// |
|
// This is the hard case. We are going to compute large positive |
|
// integers B and S and integer decExp, s.t. |
|
// d = ( B / S )// 10^decExp |
|
// 1 <= B / S < 10 |
|
// Obvious choices are: |
|
// decExp = floor( log10(d) ) |
|
// B = d// 2^nTinyBits// 10^max( 0, -decExp ) |
|
// S = 10^max( 0, decExp)// 2^nTinyBits |
|
// (noting that nTinyBits has already been forced to non-negative) |
|
// I am also going to compute a large positive integer |
|
// M = (1/2^nSignificantBits)// 2^nTinyBits// 10^max( 0, -decExp ) |
|
// i.e. M is (1/2) of the ULP of d, scaled like B. |
|
// When we iterate through dividing B/S and picking off the |
|
// quotient bits, we will know when to stop when the remainder |
|
// is <= M. |
|
// |
|
// We keep track of powers of 2 and powers of 5. |
|
|
|
int decExp = estimateDecExp(fractBits,binExp); |
|
int B2, B5; |
|
int S2, S5; |
|
int M2, M5; |
|
|
|
B5 = Math.max( 0, -decExp ); |
|
B2 = B5 + nTinyBits + binExp; |
|
|
|
S5 = Math.max( 0, decExp ); |
|
S2 = S5 + nTinyBits; |
|
|
|
M5 = B5; |
|
M2 = B2 - nSignificantBits; |
|
|
|
// |
|
// the long integer fractBits contains the (nFractBits) interesting |
|
// bits from the mantissa of d ( hidden 1 added if necessary) followed |
|
// by (EXP_SHIFT+1-nFractBits) zeros. In the interest of compactness, |
|
// I will shift out those zeros before turning fractBits into a |
|
// FDBigInteger. The resulting whole number will be |
|
// d * 2^(nFractBits-1-binExp). |
|
|
|
fractBits >>>= tailZeros; |
|
B2 -= nFractBits-1; |
|
int common2factor = Math.min( B2, S2 ); |
|
B2 -= common2factor; |
|
S2 -= common2factor; |
|
M2 -= common2factor; |
|
|
|
// |
|
// HACK!! For exact powers of two, the next smallest number |
|
// is only half as far away as we think (because the meaning of |
|
// ULP changes at power-of-two bounds) for this reason, we |
|
// hack M2. Hope this works. |
|
|
|
if ( nFractBits == 1 ) { |
|
M2 -= 1; |
|
} |
|
|
|
if ( M2 < 0 ){ |
|
// oops. |
|
// since we cannot scale M down far enough, |
|
|
|
B2 -= M2; |
|
S2 -= M2; |
|
M2 = 0; |
|
} |
|
// |
|
// Construct, Scale, iterate. |
|
// Some day, we'll write a stopping test that takes |
|
// account of the asymmetry of the spacing of floating-point |
|
// numbers below perfect powers of 2 |
|
// 26 Sept 96 is not that day. |
|
// So we use a symmetric test. |
|
|
|
int ndigit = 0; |
|
boolean low, high; |
|
long lowDigitDifference; |
|
int q; |
|
|
|
// |
|
// Detect the special cases where all the numbers we are about |
|
// to compute will fit in int or long integers. |
|
// In these cases, we will avoid doing FDBigInteger arithmetic. |
|
// We use the same algorithms, except that we "normalize" |
|
// our FDBigIntegers before iterating. This is to make division easier, |
|
// as it makes our fist guess (quotient of high-order words) |
|
// more accurate! |
|
// |
|
// Some day, we'll write a stopping test that takes |
|
// account of the asymmetry of the spacing of floating-point |
|
// numbers below perfect powers of 2 |
|
// 26 Sept 96 is not that day. |
|
// So we use a symmetric test. |
|
// |
|
|
|
int Bbits = nFractBits + B2 + (( B5 < N_5_BITS.length )? N_5_BITS[B5] : ( B5*3 )); |
|
|
|
|
|
int tenSbits = S2+1 + (( (S5+1) < N_5_BITS.length )? N_5_BITS[(S5+1)] : ( (S5+1)*3 )); |
|
if ( Bbits < 64 && tenSbits < 64){ |
|
if ( Bbits < 32 && tenSbits < 32){ |
|
|
|
int b = ((int)fractBits * FDBigInteger.SMALL_5_POW[B5] ) << B2; |
|
int s = FDBigInteger.SMALL_5_POW[S5] << S2; |
|
int m = FDBigInteger.SMALL_5_POW[M5] << M2; |
|
int tens = s * 10; |
|
// |
|
// Unroll the first iteration. If our decExp estimate |
|
// was too high, our first quotient will be zero. In this |
|
// case, we discard it and decrement decExp. |
|
|
|
ndigit = 0; |
|
q = b / s; |
|
b = 10 * ( b % s ); |
|
m *= 10; |
|
low = (b < m ); |
|
high = (b+m > tens ); |
|
assert q < 10 : q; |
|
if ( (q == 0) && ! high ){ |
|
|
|
decExp--; |
|
} else { |
|
digits[ndigit++] = (char)('0' + q); |
|
} |
|
// |
|
// HACK! Java spec sez that we always have at least |
|
// one digit after the . in either F- or E-form output. |
|
// Thus we will need more than one digit if we're using |
|
// E-form |
|
|
|
if ( !isCompatibleFormat ||decExp < -3 || decExp >= 8 ){ |
|
high = low = false; |
|
} |
|
while( ! low && ! high ){ |
|
q = b / s; |
|
b = 10 * ( b % s ); |
|
m *= 10; |
|
assert q < 10 : q; |
|
if ( m > 0L ){ |
|
low = (b < m ); |
|
high = (b+m > tens ); |
|
} else { |
|
// hack -- m might overflow! |
|
// in this case, it is certainly > b, |
|
// which won't |
|
// and b+m > tens, too, since that has overflowed |
|
|
|
low = true; |
|
high = true; |
|
} |
|
digits[ndigit++] = (char)('0' + q); |
|
} |
|
lowDigitDifference = (b<<1) - tens; |
|
exactDecimalConversion = (b == 0); |
|
} else { |
|
|
|
long b = (fractBits * FDBigInteger.LONG_5_POW[B5] ) << B2; |
|
long s = FDBigInteger.LONG_5_POW[S5] << S2; |
|
long m = FDBigInteger.LONG_5_POW[M5] << M2; |
|
long tens = s * 10L; |
|
// |
|
// Unroll the first iteration. If our decExp estimate |
|
// was too high, our first quotient will be zero. In this |
|
// case, we discard it and decrement decExp. |
|
|
|
ndigit = 0; |
|
q = (int) ( b / s ); |
|
b = 10L * ( b % s ); |
|
m *= 10L; |
|
low = (b < m ); |
|
high = (b+m > tens ); |
|
assert q < 10 : q; |
|
if ( (q == 0) && ! high ){ |
|
|
|
decExp--; |
|
} else { |
|
digits[ndigit++] = (char)('0' + q); |
|
} |
|
// |
|
// HACK! Java spec sez that we always have at least |
|
// one digit after the . in either F- or E-form output. |
|
// Thus we will need more than one digit if we're using |
|
// E-form |
|
|
|
if ( !isCompatibleFormat || decExp < -3 || decExp >= 8 ){ |
|
high = low = false; |
|
} |
|
while( ! low && ! high ){ |
|
q = (int) ( b / s ); |
|
b = 10 * ( b % s ); |
|
m *= 10; |
|
assert q < 10 : q; |
|
if ( m > 0L ){ |
|
low = (b < m ); |
|
high = (b+m > tens ); |
|
} else { |
|
// hack -- m might overflow! |
|
// in this case, it is certainly > b, |
|
// which won't |
|
// and b+m > tens, too, since that has overflowed |
|
|
|
low = true; |
|
high = true; |
|
} |
|
digits[ndigit++] = (char)('0' + q); |
|
} |
|
lowDigitDifference = (b<<1) - tens; |
|
exactDecimalConversion = (b == 0); |
|
} |
|
} else { |
|
// |
|
// We really must do FDBigInteger arithmetic. |
|
// Fist, construct our FDBigInteger initial values. |
|
|
|
FDBigInteger Sval = FDBigInteger.valueOfPow52(S5, S2); |
|
int shiftBias = Sval.getNormalizationBias(); |
|
Sval = Sval.leftShift(shiftBias); |
|
|
|
FDBigInteger Bval = FDBigInteger.valueOfMulPow52(fractBits, B5, B2 + shiftBias); |
|
FDBigInteger Mval = FDBigInteger.valueOfPow52(M5 + 1, M2 + shiftBias + 1); |
|
|
|
FDBigInteger tenSval = FDBigInteger.valueOfPow52(S5 + 1, S2 + shiftBias + 1); |
|
// |
|
// Unroll the first iteration. If our decExp estimate |
|
// was too high, our first quotient will be zero. In this |
|
// case, we discard it and decrement decExp. |
|
|
|
ndigit = 0; |
|
q = Bval.quoRemIteration( Sval ); |
|
low = (Bval.cmp( Mval ) < 0); |
|
high = tenSval.addAndCmp(Bval,Mval)<=0; |
|
|
|
assert q < 10 : q; |
|
if ( (q == 0) && ! high ){ |
|
|
|
decExp--; |
|
} else { |
|
digits[ndigit++] = (char)('0' + q); |
|
} |
|
// |
|
// HACK! Java spec sez that we always have at least |
|
// one digit after the . in either F- or E-form output. |
|
// Thus we will need more than one digit if we're using |
|
// E-form |
|
|
|
if (!isCompatibleFormat || decExp < -3 || decExp >= 8 ){ |
|
high = low = false; |
|
} |
|
while( ! low && ! high ){ |
|
q = Bval.quoRemIteration( Sval ); |
|
assert q < 10 : q; |
|
Mval = Mval.multBy10(); |
|
low = (Bval.cmp( Mval ) < 0); |
|
high = tenSval.addAndCmp(Bval,Mval)<=0; |
|
digits[ndigit++] = (char)('0' + q); |
|
} |
|
if ( high && low ){ |
|
Bval = Bval.leftShift(1); |
|
lowDigitDifference = Bval.cmp(tenSval); |
|
} else { |
|
lowDigitDifference = 0L; |
|
} |
|
exactDecimalConversion = (Bval.cmp( FDBigInteger.ZERO ) == 0); |
|
} |
|
this.decExponent = decExp+1; |
|
this.firstDigitIndex = 0; |
|
this.nDigits = ndigit; |
|
// |
|
// Last digit gets rounded based on stopping condition. |
|
|
|
if ( high ){ |
|
if ( low ){ |
|
if ( lowDigitDifference == 0L ){ |
|
// it's a tie! |
|
|
|
if ( (digits[firstDigitIndex+nDigits-1]&1) != 0 ) { |
|
roundup(); |
|
} |
|
} else if ( lowDigitDifference > 0 ){ |
|
roundup(); |
|
} |
|
} else { |
|
roundup(); |
|
} |
|
} |
|
} |
|
|
|
// add one to the least significant digit. |
|
// in the unlikely event there is a carry out, deal with it. |
|
// assert that this will only happen where there |
|
// is only one digit, e.g. (float)1e-44 seems to do it. |
|
|
|
private void roundup() { |
|
int i = (firstDigitIndex + nDigits - 1); |
|
int q = digits[i]; |
|
if (q == '9') { |
|
while (q == '9' && i > firstDigitIndex) { |
|
digits[i] = '0'; |
|
q = digits[--i]; |
|
} |
|
if (q == '9') { |
|
|
|
decExponent += 1; |
|
digits[firstDigitIndex] = '1'; |
|
return; |
|
} |
|
// else fall through. |
|
} |
|
digits[i] = (char) (q + 1); |
|
decimalDigitsRoundedUp = true; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static int estimateDecExp(long fractBits, int binExp) { |
|
double d2 = Double.longBitsToDouble( EXP_ONE | ( fractBits & DoubleConsts.SIGNIF_BIT_MASK ) ); |
|
double d = (d2-1.5D)*0.289529654D + 0.176091259 + (double)binExp * 0.301029995663981; |
|
long dBits = Double.doubleToRawLongBits(d); |
|
int exponent = (int)((dBits & DoubleConsts.EXP_BIT_MASK) >> EXP_SHIFT) - DoubleConsts.EXP_BIAS; |
|
boolean isNegative = (dBits & DoubleConsts.SIGN_BIT_MASK) != 0; |
|
if(exponent>=0 && exponent<52) { |
|
long mask = DoubleConsts.SIGNIF_BIT_MASK >> exponent; |
|
int r = (int)(( (dBits&DoubleConsts.SIGNIF_BIT_MASK) | FRACT_HOB )>>(EXP_SHIFT-exponent)); |
|
return isNegative ? (((mask & dBits) == 0L ) ? -r : -r-1 ) : r; |
|
} else if (exponent < 0) { |
|
return (((dBits&~DoubleConsts.SIGN_BIT_MASK) == 0) ? 0 : |
|
( (isNegative) ? -1 : 0) ); |
|
} else { |
|
return (int)d; |
|
} |
|
} |
|
|
|
private static int insignificantDigits(int insignificant) { |
|
int i; |
|
for ( i = 0; insignificant >= 10L; i++ ) { |
|
insignificant /= 10L; |
|
} |
|
return i; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private static int insignificantDigitsForPow2(int p2) { |
|
if(p2>1 && p2 < insignificantDigitsNumber.length) { |
|
return insignificantDigitsNumber[p2]; |
|
} |
|
return 0; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private static int[] insignificantDigitsNumber = { |
|
0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, |
|
4, 4, 4, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, |
|
8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 11, 11, 11, |
|
12, 12, 12, 12, 13, 13, 13, 14, 14, 14, |
|
15, 15, 15, 15, 16, 16, 16, 17, 17, 17, |
|
18, 18, 18, 19 |
|
}; |
|
|
|
|
|
private static final int[] N_5_BITS = { |
|
0, |
|
3, |
|
5, |
|
7, |
|
10, |
|
12, |
|
14, |
|
17, |
|
19, |
|
21, |
|
24, |
|
26, |
|
28, |
|
31, |
|
33, |
|
35, |
|
38, |
|
40, |
|
42, |
|
45, |
|
47, |
|
49, |
|
52, |
|
54, |
|
56, |
|
59, |
|
61, |
|
}; |
|
|
|
private int getChars(char[] result) { |
|
assert nDigits <= 19 : nDigits; |
|
int i = 0; |
|
if (isNegative) { |
|
result[0] = '-'; |
|
i = 1; |
|
} |
|
if (decExponent > 0 && decExponent < 8) { |
|
|
|
int charLength = Math.min(nDigits, decExponent); |
|
System.arraycopy(digits, firstDigitIndex, result, i, charLength); |
|
i += charLength; |
|
if (charLength < decExponent) { |
|
charLength = decExponent - charLength; |
|
Arrays.fill(result,i,i+charLength,'0'); |
|
i += charLength; |
|
result[i++] = '.'; |
|
result[i++] = '0'; |
|
} else { |
|
result[i++] = '.'; |
|
if (charLength < nDigits) { |
|
int t = nDigits - charLength; |
|
System.arraycopy(digits, firstDigitIndex+charLength, result, i, t); |
|
i += t; |
|
} else { |
|
result[i++] = '0'; |
|
} |
|
} |
|
} else if (decExponent <= 0 && decExponent > -3) { |
|
result[i++] = '0'; |
|
result[i++] = '.'; |
|
if (decExponent != 0) { |
|
Arrays.fill(result, i, i-decExponent, '0'); |
|
i -= decExponent; |
|
} |
|
System.arraycopy(digits, firstDigitIndex, result, i, nDigits); |
|
i += nDigits; |
|
} else { |
|
result[i++] = digits[firstDigitIndex]; |
|
result[i++] = '.'; |
|
if (nDigits > 1) { |
|
System.arraycopy(digits, firstDigitIndex+1, result, i, nDigits - 1); |
|
i += nDigits - 1; |
|
} else { |
|
result[i++] = '0'; |
|
} |
|
result[i++] = 'E'; |
|
int e; |
|
if (decExponent <= 0) { |
|
result[i++] = '-'; |
|
e = -decExponent + 1; |
|
} else { |
|
e = decExponent - 1; |
|
} |
|
|
|
if (e <= 9) { |
|
result[i++] = (char) (e + '0'); |
|
} else if (e <= 99) { |
|
result[i++] = (char) (e / 10 + '0'); |
|
result[i++] = (char) (e % 10 + '0'); |
|
} else { |
|
result[i++] = (char) (e / 100 + '0'); |
|
e %= 100; |
|
result[i++] = (char) (e / 10 + '0'); |
|
result[i++] = (char) (e % 10 + '0'); |
|
} |
|
} |
|
return i; |
|
} |
|
|
|
} |
|
|
|
private static final ThreadLocal<BinaryToASCIIBuffer> threadLocalBinaryToASCIIBuffer = |
|
new ThreadLocal<BinaryToASCIIBuffer>() { |
|
@Override |
|
protected BinaryToASCIIBuffer initialValue() { |
|
return new BinaryToASCIIBuffer(); |
|
} |
|
}; |
|
|
|
private static BinaryToASCIIBuffer getBinaryToASCIIBuffer() { |
|
return threadLocalBinaryToASCIIBuffer.get(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
interface ASCIIToBinaryConverter { |
|
|
|
double doubleValue(); |
|
|
|
float floatValue(); |
|
|
|
} |
|
|
|
|
|
|
|
*/ |
|
static class PreparedASCIIToBinaryBuffer implements ASCIIToBinaryConverter { |
|
private final double doubleVal; |
|
private final float floatVal; |
|
|
|
public PreparedASCIIToBinaryBuffer(double doubleVal, float floatVal) { |
|
this.doubleVal = doubleVal; |
|
this.floatVal = floatVal; |
|
} |
|
|
|
@Override |
|
public double doubleValue() { |
|
return doubleVal; |
|
} |
|
|
|
@Override |
|
public float floatValue() { |
|
return floatVal; |
|
} |
|
} |
|
|
|
static final ASCIIToBinaryConverter A2BC_POSITIVE_INFINITY = new PreparedASCIIToBinaryBuffer(Double.POSITIVE_INFINITY, Float.POSITIVE_INFINITY); |
|
static final ASCIIToBinaryConverter A2BC_NEGATIVE_INFINITY = new PreparedASCIIToBinaryBuffer(Double.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY); |
|
static final ASCIIToBinaryConverter A2BC_NOT_A_NUMBER = new PreparedASCIIToBinaryBuffer(Double.NaN, Float.NaN); |
|
static final ASCIIToBinaryConverter A2BC_POSITIVE_ZERO = new PreparedASCIIToBinaryBuffer(0.0d, 0.0f); |
|
static final ASCIIToBinaryConverter A2BC_NEGATIVE_ZERO = new PreparedASCIIToBinaryBuffer(-0.0d, -0.0f); |
|
|
|
|
|
|
|
*/ |
|
static class ASCIIToBinaryBuffer implements ASCIIToBinaryConverter { |
|
boolean isNegative; |
|
int decExponent; |
|
char digits[]; |
|
int nDigits; |
|
|
|
ASCIIToBinaryBuffer( boolean negSign, int decExponent, char[] digits, int n) |
|
{ |
|
this.isNegative = negSign; |
|
this.decExponent = decExponent; |
|
this.digits = digits; |
|
this.nDigits = n; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public double doubleValue() { |
|
int kDigits = Math.min(nDigits, MAX_DECIMAL_DIGITS + 1); |
|
// |
|
// convert the lead kDigits to a long integer. |
|
// |
|
|
|
int iValue = (int) digits[0] - (int) '0'; |
|
int iDigits = Math.min(kDigits, INT_DECIMAL_DIGITS); |
|
for (int i = 1; i < iDigits; i++) { |
|
iValue = iValue * 10 + (int) digits[i] - (int) '0'; |
|
} |
|
long lValue = (long) iValue; |
|
for (int i = iDigits; i < kDigits; i++) { |
|
lValue = lValue * 10L + (long) ((int) digits[i] - (int) '0'); |
|
} |
|
double dValue = (double) lValue; |
|
int exp = decExponent - kDigits; |
|
// |
|
// lValue now contains a long integer with the value of |
|
// the first kDigits digits of the number. |
|
// dValue contains the (double) of the same. |
|
// |
|
|
|
if (nDigits <= MAX_DECIMAL_DIGITS) { |
|
// |
|
// possibly an easy case. |
|
// We know that the digits can be represented |
|
// exactly. And if the exponent isn't too outrageous, |
|
// the whole thing can be done with one operation, |
|
// thus one rounding error. |
|
// Note that all our constructors trim all leading and |
|
// trailing zeros, so simple values (including zero) |
|
// will always end up here |
|
|
|
if (exp == 0 || dValue == 0.0) { |
|
return (isNegative) ? -dValue : dValue; |
|
} |
|
else if (exp >= 0) { |
|
if (exp <= MAX_SMALL_TEN) { |
|
// |
|
// Can get the answer with one operation, |
|
// thus one roundoff. |
|
|
|
double rValue = dValue * SMALL_10_POW[exp]; |
|
return (isNegative) ? -rValue : rValue; |
|
} |
|
int slop = MAX_DECIMAL_DIGITS - kDigits; |
|
if (exp <= MAX_SMALL_TEN + slop) { |
|
// |
|
// We can multiply dValue by 10^(slop) |
|
// and it is still "small" and exact. |
|
// Then we can multiply by 10^(exp-slop) |
|
// with one rounding. |
|
|
|
dValue *= SMALL_10_POW[slop]; |
|
double rValue = dValue * SMALL_10_POW[exp - slop]; |
|
return (isNegative) ? -rValue : rValue; |
|
} |
|
// |
|
// Else we have a hard case with a positive exp. |
|
// |
|
} else { |
|
if (exp >= -MAX_SMALL_TEN) { |
|
// |
|
// Can get the answer in one division. |
|
|
|
double rValue = dValue / SMALL_10_POW[-exp]; |
|
return (isNegative) ? -rValue : rValue; |
|
} |
|
// |
|
// Else we have a hard case with a negative exp. |
|
// |
|
} |
|
} |
|
|
|
// |
|
// Harder cases: |
|
// The sum of digits plus exponent is greater than |
|
// what we think we can do with one error. |
|
// |
|
// Start by approximating the right answer by, |
|
// naively, scaling by powers of 10. |
|
|
|
if (exp > 0) { |
|
if (decExponent > MAX_DECIMAL_EXPONENT + 1) { |
|
// |
|
// Lets face it. This is going to be |
|
// Infinity. Cut to the chase. |
|
|
|
return (isNegative) ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY; |
|
} |
|
if ((exp & 15) != 0) { |
|
dValue *= SMALL_10_POW[exp & 15]; |
|
} |
|
if ((exp >>= 4) != 0) { |
|
int j; |
|
for (j = 0; exp > 1; j++, exp >>= 1) { |
|
if ((exp & 1) != 0) { |
|
dValue *= BIG_10_POW[j]; |
|
} |
|
} |
|
// |
|
// The reason for the weird exp > 1 condition |
|
// in the above loop was so that the last multiply |
|
// would get unrolled. We handle it here. |
|
// It could overflow. |
|
|
|
double t = dValue * BIG_10_POW[j]; |
|
if (Double.isInfinite(t)) { |
|
// |
|
// It did overflow. |
|
// Look more closely at the result. |
|
// If the exponent is just one too large, |
|
// then use the maximum finite as our estimate |
|
// value. Else call the result infinity |
|
// and punt it. |
|
// ( I presume this could happen because |
|
// rounding forces the result here to be |
|
// an ULP or two larger than |
|
// Double.MAX_VALUE ). |
|
|
|
t = dValue / 2.0; |
|
t *= BIG_10_POW[j]; |
|
if (Double.isInfinite(t)) { |
|
return (isNegative) ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY; |
|
} |
|
t = Double.MAX_VALUE; |
|
} |
|
dValue = t; |
|
} |
|
} else if (exp < 0) { |
|
exp = -exp; |
|
if (decExponent < MIN_DECIMAL_EXPONENT - 1) { |
|
// |
|
// Lets face it. This is going to be |
|
// zero. Cut to the chase. |
|
|
|
return (isNegative) ? -0.0 : 0.0; |
|
} |
|
if ((exp & 15) != 0) { |
|
dValue /= SMALL_10_POW[exp & 15]; |
|
} |
|
if ((exp >>= 4) != 0) { |
|
int j; |
|
for (j = 0; exp > 1; j++, exp >>= 1) { |
|
if ((exp & 1) != 0) { |
|
dValue *= TINY_10_POW[j]; |
|
} |
|
} |
|
// |
|
// The reason for the weird exp > 1 condition |
|
// in the above loop was so that the last multiply |
|
// would get unrolled. We handle it here. |
|
// It could underflow. |
|
|
|
double t = dValue * TINY_10_POW[j]; |
|
if (t == 0.0) { |
|
// |
|
// It did underflow. |
|
// Look more closely at the result. |
|
// If the exponent is just one too small, |
|
// then use the minimum finite as our estimate |
|
// value. Else call the result 0.0 |
|
// and punt it. |
|
// ( I presume this could happen because |
|
// rounding forces the result here to be |
|
// an ULP or two less than |
|
// Double.MIN_VALUE ). |
|
|
|
t = dValue * 2.0; |
|
t *= TINY_10_POW[j]; |
|
if (t == 0.0) { |
|
return (isNegative) ? -0.0 : 0.0; |
|
} |
|
t = Double.MIN_VALUE; |
|
} |
|
dValue = t; |
|
} |
|
} |
|
|
|
// |
|
// dValue is now approximately the result. |
|
// The hard part is adjusting it, by comparison |
|
// with FDBigInteger arithmetic. |
|
// Formulate the EXACT big-number result as |
|
// bigD0 * 10^exp |
|
|
|
if (nDigits > MAX_NDIGITS) { |
|
nDigits = MAX_NDIGITS + 1; |
|
digits[MAX_NDIGITS] = '1'; |
|
} |
|
FDBigInteger bigD0 = new FDBigInteger(lValue, digits, kDigits, nDigits); |
|
exp = decExponent - nDigits; |
|
|
|
long ieeeBits = Double.doubleToRawLongBits(dValue); |
|
final int B5 = Math.max(0, -exp); |
|
final int D5 = Math.max(0, exp); |
|
bigD0 = bigD0.multByPow52(D5, 0); |
|
bigD0.makeImmutable(); |
|
FDBigInteger bigD = null; |
|
int prevD2 = 0; |
|
|
|
correctionLoop: |
|
while (true) { |
|
|
|
int binexp = (int) (ieeeBits >>> EXP_SHIFT); |
|
long bigBbits = ieeeBits & DoubleConsts.SIGNIF_BIT_MASK; |
|
if (binexp > 0) { |
|
bigBbits |= FRACT_HOB; |
|
} else { // Normalize denormalized numbers. |
|
assert bigBbits != 0L : bigBbits; |
|
int leadingZeros = Long.numberOfLeadingZeros(bigBbits); |
|
int shift = leadingZeros - (63 - EXP_SHIFT); |
|
bigBbits <<= shift; |
|
binexp = 1 - shift; |
|
} |
|
binexp -= DoubleConsts.EXP_BIAS; |
|
int lowOrderZeros = Long.numberOfTrailingZeros(bigBbits); |
|
bigBbits >>>= lowOrderZeros; |
|
final int bigIntExp = binexp - EXP_SHIFT + lowOrderZeros; |
|
final int bigIntNBits = EXP_SHIFT + 1 - lowOrderZeros; |
|
|
|
// |
|
// Scale bigD, bigB appropriately for |
|
// big-integer operations. |
|
// Naively, we multiply by powers of ten |
|
// and powers of two. What we actually do |
|
// is keep track of the powers of 5 and |
|
// powers of 2 we would use, then factor out |
|
// common divisors before doing the work. |
|
// |
|
int B2 = B5; |
|
int D2 = D5; |
|
int Ulp2; |
|
if (bigIntExp >= 0) { |
|
B2 += bigIntExp; |
|
} else { |
|
D2 -= bigIntExp; |
|
} |
|
Ulp2 = B2; |
|
// shift bigB and bigD left by a number s. t. |
|
|
|
int hulpbias; |
|
if (binexp <= -DoubleConsts.EXP_BIAS) { |
|
// This is going to be a denormalized number |
|
// (if not actually zero). |
|
|
|
hulpbias = binexp + lowOrderZeros + DoubleConsts.EXP_BIAS; |
|
} else { |
|
hulpbias = 1 + lowOrderZeros; |
|
} |
|
B2 += hulpbias; |
|
D2 += hulpbias; |
|
// if there are common factors of 2, we might just as well |
|
|
|
int common2 = Math.min(B2, Math.min(D2, Ulp2)); |
|
B2 -= common2; |
|
D2 -= common2; |
|
Ulp2 -= common2; |
|
|
|
FDBigInteger bigB = FDBigInteger.valueOfMulPow52(bigBbits, B5, B2); |
|
if (bigD == null || prevD2 != D2) { |
|
bigD = bigD0.leftShift(D2); |
|
prevD2 = D2; |
|
} |
|
// |
|
// to recap: |
|
// bigB is the scaled-big-int version of our floating-point |
|
// candidate. |
|
// bigD is the scaled-big-int version of the exact value |
|
// as we understand it. |
|
// halfUlp is 1/2 an ulp of bigB, except for special cases |
|
// of exact powers of 2 |
|
// |
|
// the plan is to compare bigB with bigD, and if the difference |
|
// is less than halfUlp, then we're satisfied. Otherwise, |
|
// use the ratio of difference to halfUlp to calculate a fudge |
|
// factor to add to the floating value, then go 'round again. |
|
|
|
FDBigInteger diff; |
|
int cmpResult; |
|
boolean overvalue; |
|
if ((cmpResult = bigB.cmp(bigD)) > 0) { |
|
overvalue = true; |
|
diff = bigB.leftInplaceSub(bigD); |
|
if ((bigIntNBits == 1) && (bigIntExp > -DoubleConsts.EXP_BIAS + 1)) { |
|
// candidate is a normalized exact power of 2 and |
|
// is too big (larger than Double.MIN_NORMAL). We will be subtracting. |
|
// For our purposes, ulp is the ulp of the |
|
|
|
Ulp2 -= 1; |
|
if (Ulp2 < 0) { |
|
// rats. Cannot de-scale ulp this far. |
|
|
|
Ulp2 = 0; |
|
diff = diff.leftShift(1); |
|
} |
|
} |
|
} else if (cmpResult < 0) { |
|
overvalue = false; |
|
diff = bigD.rightInplaceSub(bigB); |
|
} else { |
|
// the candidate is exactly right! |
|
|
|
break correctionLoop; |
|
} |
|
cmpResult = diff.cmpPow52(B5, Ulp2); |
|
if ((cmpResult) < 0) { |
|
// difference is small. |
|
|
|
break correctionLoop; |
|
} else if (cmpResult == 0) { |
|
// difference is exactly half an ULP |
|
|
|
if ((ieeeBits & 1) != 0) { // half ties to even |
|
ieeeBits += overvalue ? -1 : 1; |
|
} |
|
break correctionLoop; |
|
} else { |
|
// difference is non-trivial. |
|
// could scale addend by ratio of difference to |
|
// halfUlp here, if we bothered to compute that difference. |
|
// Most of the time ( I hope ) it is about 1 anyway. |
|
ieeeBits += overvalue ? -1 : 1; |
|
if (ieeeBits == 0 || ieeeBits == DoubleConsts.EXP_BIT_MASK) { // 0.0 or Double.POSITIVE_INFINITY |
|
break correctionLoop; |
|
} |
|
continue; |
|
} |
|
|
|
} |
|
if (isNegative) { |
|
ieeeBits |= DoubleConsts.SIGN_BIT_MASK; |
|
} |
|
return Double.longBitsToDouble(ieeeBits); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public float floatValue() { |
|
int kDigits = Math.min(nDigits, SINGLE_MAX_DECIMAL_DIGITS + 1); |
|
// |
|
// convert the lead kDigits to an integer. |
|
|
|
int iValue = (int) digits[0] - (int) '0'; |
|
for (int i = 1; i < kDigits; i++) { |
|
iValue = iValue * 10 + (int) digits[i] - (int) '0'; |
|
} |
|
float fValue = (float) iValue; |
|
int exp = decExponent - kDigits; |
|
// |
|
// iValue now contains an integer with the value of |
|
// the first kDigits digits of the number. |
|
// fValue contains the (float) of the same. |
|
// |
|
|
|
if (nDigits <= SINGLE_MAX_DECIMAL_DIGITS) { |
|
// |
|
// possibly an easy case. |
|
// We know that the digits can be represented |
|
// exactly. And if the exponent isn't too outrageous, |
|
// the whole thing can be done with one operation, |
|
// thus one rounding error. |
|
// Note that all our constructors trim all leading and |
|
// trailing zeros, so simple values (including zero) |
|
// will always end up here. |
|
|
|
if (exp == 0 || fValue == 0.0f) { |
|
return (isNegative) ? -fValue : fValue; |
|
} else if (exp >= 0) { |
|
if (exp <= SINGLE_MAX_SMALL_TEN) { |
|
// |
|
// Can get the answer with one operation, |
|
// thus one roundoff. |
|
|
|
fValue *= SINGLE_SMALL_10_POW[exp]; |
|
return (isNegative) ? -fValue : fValue; |
|
} |
|
int slop = SINGLE_MAX_DECIMAL_DIGITS - kDigits; |
|
if (exp <= SINGLE_MAX_SMALL_TEN + slop) { |
|
// |
|
// We can multiply fValue by 10^(slop) |
|
// and it is still "small" and exact. |
|
// Then we can multiply by 10^(exp-slop) |
|
// with one rounding. |
|
|
|
fValue *= SINGLE_SMALL_10_POW[slop]; |
|
fValue *= SINGLE_SMALL_10_POW[exp - slop]; |
|
return (isNegative) ? -fValue : fValue; |
|
} |
|
// |
|
// Else we have a hard case with a positive exp. |
|
// |
|
} else { |
|
if (exp >= -SINGLE_MAX_SMALL_TEN) { |
|
// |
|
// Can get the answer in one division. |
|
|
|
fValue /= SINGLE_SMALL_10_POW[-exp]; |
|
return (isNegative) ? -fValue : fValue; |
|
} |
|
// |
|
// Else we have a hard case with a negative exp. |
|
// |
|
} |
|
} else if ((decExponent >= nDigits) && (nDigits + decExponent <= MAX_DECIMAL_DIGITS)) { |
|
// |
|
// In double-precision, this is an exact floating integer. |
|
// So we can compute to double, then shorten to float |
|
// with one round, and get the right answer. |
|
// |
|
// First, finish accumulating digits. |
|
// Then convert that integer to a double, multiply |
|
// by the appropriate power of ten, and convert to float. |
|
|
|
long lValue = (long) iValue; |
|
for (int i = kDigits; i < nDigits; i++) { |
|
lValue = lValue * 10L + (long) ((int) digits[i] - (int) '0'); |
|
} |
|
double dValue = (double) lValue; |
|
exp = decExponent - nDigits; |
|
dValue *= SMALL_10_POW[exp]; |
|
fValue = (float) dValue; |
|
return (isNegative) ? -fValue : fValue; |
|
|
|
} |
|
// |
|
// Harder cases: |
|
// The sum of digits plus exponent is greater than |
|
// what we think we can do with one error. |
|
// |
|
// Start by approximating the right answer by, |
|
// naively, scaling by powers of 10. |
|
// Scaling uses doubles to avoid overflow/underflow. |
|
|
|
double dValue = fValue; |
|
if (exp > 0) { |
|
if (decExponent > SINGLE_MAX_DECIMAL_EXPONENT + 1) { |
|
// |
|
// Lets face it. This is going to be |
|
// Infinity. Cut to the chase. |
|
|
|
return (isNegative) ? Float.NEGATIVE_INFINITY : Float.POSITIVE_INFINITY; |
|
} |
|
if ((exp & 15) != 0) { |
|
dValue *= SMALL_10_POW[exp & 15]; |
|
} |
|
if ((exp >>= 4) != 0) { |
|
int j; |
|
for (j = 0; exp > 0; j++, exp >>= 1) { |
|
if ((exp & 1) != 0) { |
|
dValue *= BIG_10_POW[j]; |
|
} |
|
} |
|
} |
|
} else if (exp < 0) { |
|
exp = -exp; |
|
if (decExponent < SINGLE_MIN_DECIMAL_EXPONENT - 1) { |
|
// |
|
// Lets face it. This is going to be |
|
// zero. Cut to the chase. |
|
|
|
return (isNegative) ? -0.0f : 0.0f; |
|
} |
|
if ((exp & 15) != 0) { |
|
dValue /= SMALL_10_POW[exp & 15]; |
|
} |
|
if ((exp >>= 4) != 0) { |
|
int j; |
|
for (j = 0; exp > 0; j++, exp >>= 1) { |
|
if ((exp & 1) != 0) { |
|
dValue *= TINY_10_POW[j]; |
|
} |
|
} |
|
} |
|
} |
|
fValue = Math.max(Float.MIN_VALUE, Math.min(Float.MAX_VALUE, (float) dValue)); |
|
|
|
// |
|
// fValue is now approximately the result. |
|
// The hard part is adjusting it, by comparison |
|
// with FDBigInteger arithmetic. |
|
// Formulate the EXACT big-number result as |
|
// bigD0 * 10^exp |
|
|
|
if (nDigits > SINGLE_MAX_NDIGITS) { |
|
nDigits = SINGLE_MAX_NDIGITS + 1; |
|
digits[SINGLE_MAX_NDIGITS] = '1'; |
|
} |
|
FDBigInteger bigD0 = new FDBigInteger(iValue, digits, kDigits, nDigits); |
|
exp = decExponent - nDigits; |
|
|
|
int ieeeBits = Float.floatToRawIntBits(fValue); |
|
final int B5 = Math.max(0, -exp); |
|
final int D5 = Math.max(0, exp); |
|
bigD0 = bigD0.multByPow52(D5, 0); |
|
bigD0.makeImmutable(); |
|
FDBigInteger bigD = null; |
|
int prevD2 = 0; |
|
|
|
correctionLoop: |
|
while (true) { |
|
|
|
int binexp = ieeeBits >>> SINGLE_EXP_SHIFT; |
|
int bigBbits = ieeeBits & FloatConsts.SIGNIF_BIT_MASK; |
|
if (binexp > 0) { |
|
bigBbits |= SINGLE_FRACT_HOB; |
|
} else { // Normalize denormalized numbers. |
|
assert bigBbits != 0 : bigBbits; |
|
int leadingZeros = Integer.numberOfLeadingZeros(bigBbits); |
|
int shift = leadingZeros - (31 - SINGLE_EXP_SHIFT); |
|
bigBbits <<= shift; |
|
binexp = 1 - shift; |
|
} |
|
binexp -= FloatConsts.EXP_BIAS; |
|
int lowOrderZeros = Integer.numberOfTrailingZeros(bigBbits); |
|
bigBbits >>>= lowOrderZeros; |
|
final int bigIntExp = binexp - SINGLE_EXP_SHIFT + lowOrderZeros; |
|
final int bigIntNBits = SINGLE_EXP_SHIFT + 1 - lowOrderZeros; |
|
|
|
// |
|
// Scale bigD, bigB appropriately for |
|
// big-integer operations. |
|
// Naively, we multiply by powers of ten |
|
// and powers of two. What we actually do |
|
// is keep track of the powers of 5 and |
|
// powers of 2 we would use, then factor out |
|
// common divisors before doing the work. |
|
// |
|
int B2 = B5; |
|
int D2 = D5; |
|
int Ulp2; |
|
if (bigIntExp >= 0) { |
|
B2 += bigIntExp; |
|
} else { |
|
D2 -= bigIntExp; |
|
} |
|
Ulp2 = B2; |
|
// shift bigB and bigD left by a number s. t. |
|
|
|
int hulpbias; |
|
if (binexp <= -FloatConsts.EXP_BIAS) { |
|
// This is going to be a denormalized number |
|
// (if not actually zero). |
|
|
|
hulpbias = binexp + lowOrderZeros + FloatConsts.EXP_BIAS; |
|
} else { |
|
hulpbias = 1 + lowOrderZeros; |
|
} |
|
B2 += hulpbias; |
|
D2 += hulpbias; |
|
// if there are common factors of 2, we might just as well |
|
|
|
int common2 = Math.min(B2, Math.min(D2, Ulp2)); |
|
B2 -= common2; |
|
D2 -= common2; |
|
Ulp2 -= common2; |
|
|
|
FDBigInteger bigB = FDBigInteger.valueOfMulPow52(bigBbits, B5, B2); |
|
if (bigD == null || prevD2 != D2) { |
|
bigD = bigD0.leftShift(D2); |
|
prevD2 = D2; |
|
} |
|
// |
|
// to recap: |
|
// bigB is the scaled-big-int version of our floating-point |
|
// candidate. |
|
// bigD is the scaled-big-int version of the exact value |
|
// as we understand it. |
|
// halfUlp is 1/2 an ulp of bigB, except for special cases |
|
// of exact powers of 2 |
|
// |
|
// the plan is to compare bigB with bigD, and if the difference |
|
// is less than halfUlp, then we're satisfied. Otherwise, |
|
// use the ratio of difference to halfUlp to calculate a fudge |
|
// factor to add to the floating value, then go 'round again. |
|
|
|
FDBigInteger diff; |
|
int cmpResult; |
|
boolean overvalue; |
|
if ((cmpResult = bigB.cmp(bigD)) > 0) { |
|
overvalue = true; |
|
diff = bigB.leftInplaceSub(bigD); |
|
if ((bigIntNBits == 1) && (bigIntExp > -FloatConsts.EXP_BIAS + 1)) { |
|
// candidate is a normalized exact power of 2 and |
|
// is too big (larger than Float.MIN_NORMAL). We will be subtracting. |
|
// For our purposes, ulp is the ulp of the |
|
|
|
Ulp2 -= 1; |
|
if (Ulp2 < 0) { |
|
// rats. Cannot de-scale ulp this far. |
|
|
|
Ulp2 = 0; |
|
diff = diff.leftShift(1); |
|
} |
|
} |
|
} else if (cmpResult < 0) { |
|
overvalue = false; |
|
diff = bigD.rightInplaceSub(bigB); |
|
} else { |
|
// the candidate is exactly right! |
|
|
|
break correctionLoop; |
|
} |
|
cmpResult = diff.cmpPow52(B5, Ulp2); |
|
if ((cmpResult) < 0) { |
|
// difference is small. |
|
|
|
break correctionLoop; |
|
} else if (cmpResult == 0) { |
|
// difference is exactly half an ULP |
|
|
|
if ((ieeeBits & 1) != 0) { // half ties to even |
|
ieeeBits += overvalue ? -1 : 1; |
|
} |
|
break correctionLoop; |
|
} else { |
|
// difference is non-trivial. |
|
// could scale addend by ratio of difference to |
|
// halfUlp here, if we bothered to compute that difference. |
|
// Most of the time ( I hope ) it is about 1 anyway. |
|
ieeeBits += overvalue ? -1 : 1; |
|
if (ieeeBits == 0 || ieeeBits == FloatConsts.EXP_BIT_MASK) { // 0.0 or Float.POSITIVE_INFINITY |
|
break correctionLoop; |
|
} |
|
continue; |
|
} |
|
|
|
} |
|
if (isNegative) { |
|
ieeeBits |= FloatConsts.SIGN_BIT_MASK; |
|
} |
|
return Float.intBitsToFloat(ieeeBits); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private static final double[] SMALL_10_POW = { |
|
1.0e0, |
|
1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5, |
|
1.0e6, 1.0e7, 1.0e8, 1.0e9, 1.0e10, |
|
1.0e11, 1.0e12, 1.0e13, 1.0e14, 1.0e15, |
|
1.0e16, 1.0e17, 1.0e18, 1.0e19, 1.0e20, |
|
1.0e21, 1.0e22 |
|
}; |
|
|
|
private static final float[] SINGLE_SMALL_10_POW = { |
|
1.0e0f, |
|
1.0e1f, 1.0e2f, 1.0e3f, 1.0e4f, 1.0e5f, |
|
1.0e6f, 1.0e7f, 1.0e8f, 1.0e9f, 1.0e10f |
|
}; |
|
|
|
private static final double[] BIG_10_POW = { |
|
1e16, 1e32, 1e64, 1e128, 1e256 }; |
|
private static final double[] TINY_10_POW = { |
|
1e-16, 1e-32, 1e-64, 1e-128, 1e-256 }; |
|
|
|
private static final int MAX_SMALL_TEN = SMALL_10_POW.length-1; |
|
private static final int SINGLE_MAX_SMALL_TEN = SINGLE_SMALL_10_POW.length-1; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static BinaryToASCIIConverter getBinaryToASCIIConverter(double d) { |
|
return getBinaryToASCIIConverter(d, true); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static BinaryToASCIIConverter getBinaryToASCIIConverter(double d, boolean isCompatibleFormat) { |
|
long dBits = Double.doubleToRawLongBits(d); |
|
boolean isNegative = (dBits&DoubleConsts.SIGN_BIT_MASK) != 0; |
|
long fractBits = dBits & DoubleConsts.SIGNIF_BIT_MASK; |
|
int binExp = (int)( (dBits&DoubleConsts.EXP_BIT_MASK) >> EXP_SHIFT ); |
|
|
|
if ( binExp == (int)(DoubleConsts.EXP_BIT_MASK>>EXP_SHIFT) ) { |
|
if ( fractBits == 0L ){ |
|
return isNegative ? B2AC_NEGATIVE_INFINITY : B2AC_POSITIVE_INFINITY; |
|
} else { |
|
return B2AC_NOT_A_NUMBER; |
|
} |
|
} |
|
// Finish unpacking |
|
// Normalize denormalized numbers. |
|
// Insert assumed high-order bit for normalized numbers. |
|
|
|
int nSignificantBits; |
|
if ( binExp == 0 ){ |
|
if ( fractBits == 0L ){ |
|
|
|
return isNegative ? B2AC_NEGATIVE_ZERO : B2AC_POSITIVE_ZERO; |
|
} |
|
int leadingZeros = Long.numberOfLeadingZeros(fractBits); |
|
int shift = leadingZeros-(63-EXP_SHIFT); |
|
fractBits <<= shift; |
|
binExp = 1 - shift; |
|
nSignificantBits = 64-leadingZeros; |
|
} else { |
|
fractBits |= FRACT_HOB; |
|
nSignificantBits = EXP_SHIFT+1; |
|
} |
|
binExp -= DoubleConsts.EXP_BIAS; |
|
BinaryToASCIIBuffer buf = getBinaryToASCIIBuffer(); |
|
buf.setSign(isNegative); |
|
|
|
buf.dtoa(binExp, fractBits, nSignificantBits, isCompatibleFormat); |
|
return buf; |
|
} |
|
|
|
private static BinaryToASCIIConverter getBinaryToASCIIConverter(float f) { |
|
int fBits = Float.floatToRawIntBits( f ); |
|
boolean isNegative = (fBits&FloatConsts.SIGN_BIT_MASK) != 0; |
|
int fractBits = fBits&FloatConsts.SIGNIF_BIT_MASK; |
|
int binExp = (fBits&FloatConsts.EXP_BIT_MASK) >> SINGLE_EXP_SHIFT; |
|
|
|
if ( binExp == (FloatConsts.EXP_BIT_MASK>>SINGLE_EXP_SHIFT) ) { |
|
if ( fractBits == 0L ){ |
|
return isNegative ? B2AC_NEGATIVE_INFINITY : B2AC_POSITIVE_INFINITY; |
|
} else { |
|
return B2AC_NOT_A_NUMBER; |
|
} |
|
} |
|
// Finish unpacking |
|
// Normalize denormalized numbers. |
|
// Insert assumed high-order bit for normalized numbers. |
|
|
|
int nSignificantBits; |
|
if ( binExp == 0 ){ |
|
if ( fractBits == 0 ){ |
|
|
|
return isNegative ? B2AC_NEGATIVE_ZERO : B2AC_POSITIVE_ZERO; |
|
} |
|
int leadingZeros = Integer.numberOfLeadingZeros(fractBits); |
|
int shift = leadingZeros-(31-SINGLE_EXP_SHIFT); |
|
fractBits <<= shift; |
|
binExp = 1 - shift; |
|
nSignificantBits = 32 - leadingZeros; |
|
} else { |
|
fractBits |= SINGLE_FRACT_HOB; |
|
nSignificantBits = SINGLE_EXP_SHIFT+1; |
|
} |
|
binExp -= FloatConsts.EXP_BIAS; |
|
BinaryToASCIIBuffer buf = getBinaryToASCIIBuffer(); |
|
buf.setSign(isNegative); |
|
|
|
buf.dtoa(binExp, ((long)fractBits)<<(EXP_SHIFT-SINGLE_EXP_SHIFT), nSignificantBits, true); |
|
return buf; |
|
} |
|
|
|
@SuppressWarnings("fallthrough") |
|
static ASCIIToBinaryConverter readJavaFormatString( String in ) throws NumberFormatException { |
|
boolean isNegative = false; |
|
boolean signSeen = false; |
|
int decExp; |
|
char c; |
|
|
|
parseNumber: |
|
try{ |
|
in = in.trim(); |
|
|
|
int len = in.length(); |
|
if ( len == 0 ) { |
|
throw new NumberFormatException("empty String"); |
|
} |
|
int i = 0; |
|
switch (in.charAt(i)){ |
|
case '-': |
|
isNegative = true; |
|
|
|
case '+': |
|
i++; |
|
signSeen = true; |
|
} |
|
c = in.charAt(i); |
|
if(c == 'N') { |
|
if((len-i)==NAN_LENGTH && in.indexOf(NAN_REP,i)==i) { |
|
return A2BC_NOT_A_NUMBER; |
|
} |
|
|
|
break parseNumber; |
|
} else if(c == 'I') { |
|
if((len-i)==INFINITY_LENGTH && in.indexOf(INFINITY_REP,i)==i) { |
|
return isNegative? A2BC_NEGATIVE_INFINITY : A2BC_POSITIVE_INFINITY; |
|
} |
|
|
|
break parseNumber; |
|
} else if (c == '0') { |
|
if (len > i+1 ) { |
|
char ch = in.charAt(i+1); |
|
if (ch == 'x' || ch == 'X' ) { |
|
return parseHexString(in); |
|
} |
|
} |
|
} // look for and process decimal floating-point string |
|
|
|
char[] digits = new char[ len ]; |
|
int nDigits= 0; |
|
boolean decSeen = false; |
|
int decPt = 0; |
|
int nLeadZero = 0; |
|
int nTrailZero= 0; |
|
|
|
skipLeadingZerosLoop: |
|
while (i < len) { |
|
c = in.charAt(i); |
|
if (c == '0') { |
|
nLeadZero++; |
|
} else if (c == '.') { |
|
if (decSeen) { |
|
|
|
throw new NumberFormatException("multiple points"); |
|
} |
|
decPt = i; |
|
if (signSeen) { |
|
decPt -= 1; |
|
} |
|
decSeen = true; |
|
} else { |
|
break skipLeadingZerosLoop; |
|
} |
|
i++; |
|
} |
|
digitLoop: |
|
while (i < len) { |
|
c = in.charAt(i); |
|
if (c >= '1' && c <= '9') { |
|
digits[nDigits++] = c; |
|
nTrailZero = 0; |
|
} else if (c == '0') { |
|
digits[nDigits++] = c; |
|
nTrailZero++; |
|
} else if (c == '.') { |
|
if (decSeen) { |
|
|
|
throw new NumberFormatException("multiple points"); |
|
} |
|
decPt = i; |
|
if (signSeen) { |
|
decPt -= 1; |
|
} |
|
decSeen = true; |
|
} else { |
|
break digitLoop; |
|
} |
|
i++; |
|
} |
|
nDigits -=nTrailZero; |
|
// |
|
// At this point, we've scanned all the digits and decimal |
|
// point we're going to see. Trim off leading and trailing |
|
// zeros, which will just confuse us later, and adjust |
|
// our initial decimal exponent accordingly. |
|
// To review: |
|
// we have seen i total characters. |
|
// nLeadZero of them were zeros before any other digits. |
|
// nTrailZero of them were zeros after any other digits. |
|
// if ( decSeen ), then a . was seen after decPt characters |
|
// ( including leading zeros which have been discarded ) |
|
// nDigits characters were neither lead nor trailing |
|
// zeros, nor point |
|
// |
|
// |
|
// special hack: if we saw no non-zero digits, then the |
|
// answer is zero! |
|
// Unfortunately, we feel honor-bound to keep parsing! |
|
|
|
boolean isZero = (nDigits == 0); |
|
if ( isZero && nLeadZero == 0 ){ |
|
// we saw NO DIGITS AT ALL, |
|
// not even a crummy 0! |
|
// this is not allowed. |
|
break parseNumber; |
|
} |
|
// |
|
// Our initial exponent is decPt, adjusted by the number of |
|
// discarded zeros. Or, if there was no decPt, |
|
// then its just nDigits adjusted by discarded trailing zeros. |
|
|
|
if ( decSeen ){ |
|
decExp = decPt - nLeadZero; |
|
} else { |
|
decExp = nDigits + nTrailZero; |
|
} |
|
|
|
// |
|
// Look for 'e' or 'E' and an optionally signed integer. |
|
|
|
if ( (i < len) && (((c = in.charAt(i) )=='e') || (c == 'E') ) ){ |
|
int expSign = 1; |
|
int expVal = 0; |
|
int reallyBig = Integer.MAX_VALUE / 10; |
|
boolean expOverflow = false; |
|
switch( in.charAt(++i) ){ |
|
case '-': |
|
expSign = -1; |
|
|
|
case '+': |
|
i++; |
|
} |
|
int expAt = i; |
|
expLoop: |
|
while ( i < len ){ |
|
if ( expVal >= reallyBig ){ |
|
// the next character will cause integer |
|
|
|
expOverflow = true; |
|
} |
|
c = in.charAt(i++); |
|
if(c>='0' && c<='9') { |
|
expVal = expVal*10 + ( (int)c - (int)'0' ); |
|
} else { |
|
i--; |
|
break expLoop; |
|
} |
|
} |
|
int expLimit = BIG_DECIMAL_EXPONENT + nDigits + nTrailZero; |
|
if (expOverflow || (expVal > expLimit)) { |
|
// There is still a chance that the exponent will be safe to |
|
// use: if it would eventually decrease due to a negative |
|
// decExp, and that number is below the limit. We check for |
|
|
|
if (!expOverflow && (expSign == 1 && decExp < 0) |
|
&& (expVal + decExp) < expLimit) { |
|
|
|
decExp += expVal; |
|
} else { |
|
// |
|
// The intent here is to end up with |
|
// infinity or zero, as appropriate. |
|
// The reason for yielding such a small decExponent, |
|
// rather than something intuitive such as |
|
// expSign*Integer.MAX_VALUE, is that this value |
|
// is subject to further manipulation in |
|
// doubleValue() and floatValue(), and I don't want |
|
// it to be able to cause overflow there! |
|
// (The only way we can get into trouble here is for |
|
// really outrageous nDigits+nTrailZero, such as 2 |
|
// billion.) |
|
|
|
decExp = expSign * expLimit; |
|
} |
|
} else { |
|
// this should not overflow, since we tested |
|
|
|
decExp = decExp + expSign*expVal; |
|
} |
|
|
|
// if we saw something not a digit ( or end of string ) |
|
// after the [Ee][+-], without seeing any digits at all |
|
// this is certainly an error. If we saw some digits, |
|
// but then some trailing garbage, that might be ok. |
|
// so we just fall through in that case. |
|
|
|
if ( i == expAt ) { |
|
break parseNumber; |
|
} |
|
} |
|
// |
|
// We parsed everything we could. |
|
// If there are leftovers, then this is not good input! |
|
|
|
if ( i < len && |
|
((i != len - 1) || |
|
(in.charAt(i) != 'f' && |
|
in.charAt(i) != 'F' && |
|
in.charAt(i) != 'd' && |
|
in.charAt(i) != 'D'))) { |
|
break parseNumber; |
|
} |
|
if(isZero) { |
|
return isNegative ? A2BC_NEGATIVE_ZERO : A2BC_POSITIVE_ZERO; |
|
} |
|
return new ASCIIToBinaryBuffer(isNegative, decExp, digits, nDigits); |
|
} catch ( StringIndexOutOfBoundsException e ){ } |
|
throw new NumberFormatException("For input string: \"" + in + "\""); |
|
} |
|
|
|
private static class HexFloatPattern { |
|
|
|
|
|
|
|
*/ |
|
private static final Pattern VALUE = Pattern.compile( |
|
|
|
"([-+])?0[xX](((\\p{XDigit}+)\\.?)|((\\p{XDigit}*)\\.(\\p{XDigit}+)))[pP]([-+])?(\\p{Digit}+)[fFdD]?" |
|
); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static ASCIIToBinaryConverter parseHexString(String s) { |
|
// Verify string is a member of the hexadecimal floating-point |
|
|
|
Matcher m = HexFloatPattern.VALUE.matcher(s); |
|
boolean validInput = m.matches(); |
|
if (!validInput) { |
|
|
|
throw new NumberFormatException("For input string: \"" + s + "\""); |
|
} else { // validInput |
|
// |
|
// We must isolate the sign, significand, and exponent |
|
// fields. The sign value is straightforward. Since |
|
// floating-point numbers are stored with a normalized |
|
// representation, the significand and exponent are |
|
// interrelated. |
|
// |
|
// After extracting the sign, we normalized the |
|
// significand as a hexadecimal value, calculating an |
|
// exponent adjust for any shifts made during |
|
// normalization. If the significand is zero, the |
|
// exponent doesn't need to be examined since the output |
|
// will be zero. |
|
// |
|
// Next the exponent in the input string is extracted. |
|
// Afterwards, the significand is normalized as a *binary* |
|
// value and the input value's normalized exponent can be |
|
// computed. The significand bits are copied into a |
|
// double significand; if the string has more logical bits |
|
// than can fit in a double, the extra bits affect the |
|
// round and sticky bits which are used to round the final |
|
// value. |
|
// |
|
|
|
String group1 = m.group(1); |
|
boolean isNegative = ((group1 != null) && group1.equals("-")); |
|
|
|
// Extract Significand magnitude |
|
// |
|
// Based on the form of the significand, calculate how the |
|
// binary exponent needs to be adjusted to create a |
|
// normalized//hexadecimal* floating-point number; that |
|
// is, a number where there is one nonzero hex digit to |
|
// the left of the (hexa)decimal point. Since we are |
|
// adjusting a binary, not hexadecimal exponent, the |
|
// exponent is adjusted by a multiple of 4. |
|
// |
|
// There are a number of significand scenarios to consider; |
|
// letters are used in indicate nonzero digits: |
|
// |
|
// 1. 000xxxx => x.xxx normalized |
|
// increase exponent by (number of x's - 1)*4 |
|
// |
|
// 2. 000xxx.yyyy => x.xxyyyy normalized |
|
// increase exponent by (number of x's - 1)*4 |
|
// |
|
// 3. .000yyy => y.yy normalized |
|
// decrease exponent by (number of zeros + 1)*4 |
|
// |
|
// 4. 000.00000yyy => y.yy normalized |
|
// decrease exponent by (number of zeros to right of point + 1)*4 |
|
// |
|
// If the significand is exactly zero, return a properly |
|
// signed zero. |
|
// |
|
|
|
String significandString = null; |
|
int signifLength = 0; |
|
int exponentAdjust = 0; |
|
{ |
|
int leftDigits = 0; |
|
// left of "decimal" point |
|
// (leading zeros stripped) |
|
int rightDigits = 0; |
|
// "decimal" point; leading zeros |
|
// must always be accounted for |
|
// |
|
// The significand is made up of either |
|
// |
|
// 1. group 4 entirely (integer portion only) |
|
// |
|
// OR |
|
// |
|
// 2. the fractional portion from group 7 plus any |
|
// (optional) integer portions from group 6. |
|
|
|
String group4; |
|
if ((group4 = m.group(4)) != null) { // Integer-only significand |
|
|
|
significandString = stripLeadingZeros(group4); |
|
leftDigits = significandString.length(); |
|
} else { |
|
// Group 6 is the optional integer; leading zeros |
|
|
|
String group6 = stripLeadingZeros(m.group(6)); |
|
leftDigits = group6.length(); |
|
|
|
|
|
String group7 = m.group(7); |
|
rightDigits = group7.length(); |
|
|
|
|
|
significandString = |
|
((group6 == null) ? "" : group6) + |
|
|
|
group7; |
|
} |
|
|
|
significandString = stripLeadingZeros(significandString); |
|
signifLength = significandString.length(); |
|
|
|
// |
|
// Adjust exponent as described above |
|
|
|
if (leftDigits >= 1) { |
|
exponentAdjust = 4 * (leftDigits - 1); |
|
} else { |
|
exponentAdjust = -4 * (rightDigits - signifLength + 1); |
|
} |
|
|
|
// If the significand is zero, the exponent doesn't |
|
// matter; return a properly signed zero. |
|
|
|
if (signifLength == 0) { |
|
return isNegative ? A2BC_NEGATIVE_ZERO : A2BC_POSITIVE_ZERO; |
|
} |
|
} |
|
|
|
// Extract Exponent |
|
// |
|
// Use an int to read in the exponent value; this should |
|
// provide more than sufficient range for non-contrived |
|
// inputs. If reading the exponent in as an int does |
|
// overflow, examine the sign of the exponent and |
|
// significand to determine what to do. |
|
|
|
String group8 = m.group(8); |
|
boolean positiveExponent = (group8 == null) || group8.equals("+"); |
|
long unsignedRawExponent; |
|
try { |
|
unsignedRawExponent = Integer.parseInt(m.group(9)); |
|
} |
|
catch (NumberFormatException e) { |
|
// At this point, we know the exponent is |
|
// syntactically well-formed as a sequence of |
|
// digits. Therefore, if an NumberFormatException |
|
// is thrown, it must be due to overflowing int's |
|
// range. Also, at this point, we have already |
|
// checked for a zero significand. Thus the signs |
|
// of the exponent and significand determine the |
|
// final result: |
|
// |
|
// significand |
|
// + - |
|
// exponent + +infinity -infinity |
|
|
|
return isNegative ? |
|
(positiveExponent ? A2BC_NEGATIVE_INFINITY : A2BC_NEGATIVE_ZERO) |
|
: (positiveExponent ? A2BC_POSITIVE_INFINITY : A2BC_POSITIVE_ZERO); |
|
|
|
} |
|
|
|
long rawExponent = |
|
(positiveExponent ? 1L : -1L) * |
|
unsignedRawExponent; |
|
|
|
|
|
long exponent = rawExponent + exponentAdjust; |
|
|
|
// Starting copying non-zero bits into proper position in |
|
// a long; copy explicit bit too; this will be masked |
|
// later for normal values. |
|
|
|
boolean round = false; |
|
boolean sticky = false; |
|
int nextShift = 0; |
|
long significand = 0L; |
|
// First iteration is different, since we only copy |
|
// from the leading significand bit; one more exponent |
|
// adjust will be needed... |
|
|
|
// IMPORTANT: make leadingDigit a long to avoid |
|
|
|
long leadingDigit = getHexDigit(significandString, 0); |
|
|
|
// |
|
// Left shift the leading digit (53 - (bit position of |
|
// leading 1 in digit)); this sets the top bit of the |
|
// significand to 1. The nextShift value is adjusted |
|
// to take into account the number of bit positions of |
|
// the leadingDigit actually used. Finally, the |
|
// exponent is adjusted to normalize the significand |
|
// as a binary value, not just a hex value. |
|
|
|
if (leadingDigit == 1) { |
|
significand |= leadingDigit << 52; |
|
nextShift = 52 - 4; |
|
// exponent += 0 |
|
} else if (leadingDigit <= 3) { |
|
significand |= leadingDigit << 51; |
|
nextShift = 52 - 5; |
|
exponent += 1; |
|
} else if (leadingDigit <= 7) { |
|
significand |= leadingDigit << 50; |
|
nextShift = 52 - 6; |
|
exponent += 2; |
|
} else if (leadingDigit <= 15) { |
|
significand |= leadingDigit << 49; |
|
nextShift = 52 - 7; |
|
exponent += 3; |
|
} else { |
|
throw new AssertionError("Result from digit conversion too large!"); |
|
} |
|
// The preceding if-else could be replaced by a single |
|
// code block based on the high-order bit set in |
|
// leadingDigit. Given leadingOnePosition, |
|
|
|
// significand |= leadingDigit << (SIGNIFICAND_WIDTH - leadingOnePosition); |
|
// nextShift = 52 - (3 + leadingOnePosition); |
|
// exponent += (leadingOnePosition-1); |
|
|
|
// |
|
// Now the exponent variable is equal to the normalized |
|
// binary exponent. Code below will make representation |
|
// adjustments if the exponent is incremented after |
|
// rounding (includes overflows to infinity) or if the |
|
// result is subnormal. |
|
// |
|
|
|
// Copy digit into significand until the significand can't |
|
// hold another full hex digit or there are no more input |
|
|
|
int i = 0; |
|
for (i = 1; |
|
i < signifLength && nextShift >= 0; |
|
i++) { |
|
long currentDigit = getHexDigit(significandString, i); |
|
significand |= (currentDigit << nextShift); |
|
nextShift -= 4; |
|
} |
|
|
|
// After the above loop, the bulk of the string is copied. |
|
// Now, we must copy any partial hex digits into the |
|
// significand AND compute the round bit and start computing |
|
// sticky bit. |
|
|
|
if (i < signifLength) { |
|
long currentDigit = getHexDigit(significandString, i); |
|
|
|
// from nextShift, figure out how many bits need |
|
|
|
switch (nextShift) { |
|
case -1: |
|
// three bits need to be copied in; can |
|
|
|
significand |= ((currentDigit & 0xEL) >> 1); |
|
round = (currentDigit & 0x1L) != 0L; |
|
break; |
|
|
|
case -2: |
|
// two bits need to be copied in; can |
|
|
|
significand |= ((currentDigit & 0xCL) >> 2); |
|
round = (currentDigit & 0x2L) != 0L; |
|
sticky = (currentDigit & 0x1L) != 0; |
|
break; |
|
|
|
case -3: |
|
|
|
significand |= ((currentDigit & 0x8L) >> 3); |
|
|
|
round = (currentDigit & 0x4L) != 0L; |
|
sticky = (currentDigit & 0x3L) != 0; |
|
break; |
|
|
|
case -4: |
|
// all bits copied into significand; set |
|
// round and start sticky |
|
round = ((currentDigit & 0x8L) != 0); |
|
|
|
sticky = (currentDigit & 0x7L) != 0; |
|
break; |
|
|
|
default: |
|
throw new AssertionError("Unexpected shift distance remainder."); |
|
// break; |
|
} |
|
|
|
// Round is set; sticky might be set. |
|
|
|
// For the sticky bit, it suffices to check the |
|
// current digit and test for any nonzero digits in |
|
|
|
i++; |
|
while (i < signifLength && !sticky) { |
|
currentDigit = getHexDigit(significandString, i); |
|
sticky = sticky || (currentDigit != 0); |
|
i++; |
|
} |
|
|
|
} |
|
// else all of string was seen, round and sticky are |
|
// correct as false. |
|
|
|
|
|
int floatBits = isNegative ? FloatConsts.SIGN_BIT_MASK : 0; |
|
if (exponent >= Float.MIN_EXPONENT) { |
|
if (exponent > Float.MAX_EXPONENT) { |
|
|
|
floatBits |= FloatConsts.EXP_BIT_MASK; |
|
} else { |
|
int threshShift = DoubleConsts.SIGNIFICAND_WIDTH - FloatConsts.SIGNIFICAND_WIDTH - 1; |
|
boolean floatSticky = (significand & ((1L << threshShift) - 1)) != 0 || round || sticky; |
|
int iValue = (int) (significand >>> threshShift); |
|
if ((iValue & 3) != 1 || floatSticky) { |
|
iValue++; |
|
} |
|
floatBits |= (((((int) exponent) + (FloatConsts.EXP_BIAS - 1))) << SINGLE_EXP_SHIFT) + (iValue >> 1); |
|
} |
|
} else { |
|
if (exponent < FloatConsts.MIN_SUB_EXPONENT - 1) { |
|
// 0 |
|
} else { |
|
|
|
int threshShift = (int) ((DoubleConsts.SIGNIFICAND_WIDTH - 2 + FloatConsts.MIN_SUB_EXPONENT) - exponent); |
|
assert threshShift >= DoubleConsts.SIGNIFICAND_WIDTH - FloatConsts.SIGNIFICAND_WIDTH; |
|
assert threshShift < DoubleConsts.SIGNIFICAND_WIDTH; |
|
boolean floatSticky = (significand & ((1L << threshShift) - 1)) != 0 || round || sticky; |
|
int iValue = (int) (significand >>> threshShift); |
|
if ((iValue & 3) != 1 || floatSticky) { |
|
iValue++; |
|
} |
|
floatBits |= iValue >> 1; |
|
} |
|
} |
|
float fValue = Float.intBitsToFloat(floatBits); |
|
|
|
|
|
if (exponent > Double.MAX_EXPONENT) { // Infinite result |
|
|
|
return isNegative ? A2BC_NEGATIVE_INFINITY : A2BC_POSITIVE_INFINITY; |
|
} else { |
|
if (exponent <= Double.MAX_EXPONENT && |
|
exponent >= Double.MIN_EXPONENT) { |
|
|
|
// The result returned in this block cannot be a |
|
// zero or subnormal; however after the |
|
// significand is adjusted from rounding, we could |
|
// still overflow in infinity. |
|
|
|
// AND exponent bits into significand; if the |
|
// significand is incremented and overflows from |
|
// rounding, this combination will update the |
|
// exponent correctly, even in the case of |
|
// Double.MAX_VALUE overflowing to infinity. |
|
|
|
significand = ((( exponent + |
|
(long) DoubleConsts.EXP_BIAS) << |
|
(DoubleConsts.SIGNIFICAND_WIDTH - 1)) |
|
& DoubleConsts.EXP_BIT_MASK) | |
|
(DoubleConsts.SIGNIF_BIT_MASK & significand); |
|
|
|
} else { // Subnormal or zero |
|
// (exponent < Double.MIN_EXPONENT) |
|
|
|
if (exponent < (DoubleConsts.MIN_SUB_EXPONENT - 1)) { |
|
// No way to round back to nonzero value |
|
// regardless of significand if the exponent is |
|
|
|
return isNegative ? A2BC_NEGATIVE_ZERO : A2BC_POSITIVE_ZERO; |
|
} else { // -1075 <= exponent <= MIN_EXPONENT -1 = -1023 |
|
// |
|
// Find bit position to round to; recompute |
|
// round and sticky bits, and shift |
|
// significand right appropriately. |
|
// |
|
|
|
sticky = sticky || round; |
|
round = false; |
|
|
|
// Number of bits of significand to preserve is |
|
// exponent - abs_min_exp +1 |
|
// check: |
|
// -1075 +1074 + 1 = 0 |
|
// -1023 +1074 + 1 = 52 |
|
|
|
int bitsDiscarded = 53 - |
|
((int) exponent - DoubleConsts.MIN_SUB_EXPONENT + 1); |
|
assert bitsDiscarded >= 1 && bitsDiscarded <= 53; |
|
|
|
// What to do here: |
|
|
|
round = (significand & (1L << (bitsDiscarded - 1))) != 0L; |
|
if (bitsDiscarded > 1) { |
|
// create mask to update sticky bits; low |
|
|
|
long mask = ~((~0L) << (bitsDiscarded - 1)); |
|
sticky = sticky || ((significand & mask) != 0L); |
|
} |
|
|
|
|
|
significand = significand >> bitsDiscarded; |
|
|
|
significand = ((((long) (Double.MIN_EXPONENT - 1) + |
|
(long) DoubleConsts.EXP_BIAS) << |
|
(DoubleConsts.SIGNIFICAND_WIDTH - 1)) |
|
& DoubleConsts.EXP_BIT_MASK) | |
|
(DoubleConsts.SIGNIF_BIT_MASK & significand); |
|
} |
|
} |
|
|
|
// The significand variable now contains the currently |
|
// appropriate exponent bits too. |
|
|
|
// |
|
// Determine if significand should be incremented; |
|
// making this determination depends on the least |
|
// significant bit and the round and sticky bits. |
|
// |
|
// Round to nearest even rounding table, adapted from |
|
// table 4.7 in "Computer Arithmetic" by IsraelKoren. |
|
// The digit to the left of the "decimal" point is the |
|
// least significant bit, the digits to the right of |
|
// the point are the round and sticky bits |
|
// |
|
// Number Round(x) |
|
// x0.00 x0. |
|
// x0.01 x0. |
|
// x0.10 x0. |
|
// x0.11 x1. = x0. +1 |
|
// x1.00 x1. |
|
// x1.01 x1. |
|
// x1.10 x1. + 1 |
|
// x1.11 x1. + 1 |
|
|
|
boolean leastZero = ((significand & 1L) == 0L); |
|
if ((leastZero && round && sticky) || |
|
((!leastZero) && round)) { |
|
significand++; |
|
} |
|
|
|
double value = isNegative ? |
|
Double.longBitsToDouble(significand | DoubleConsts.SIGN_BIT_MASK) : |
|
Double.longBitsToDouble(significand ); |
|
|
|
return new PreparedASCIIToBinaryBuffer(value, fValue); |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
static String stripLeadingZeros(String s) { |
|
|
|
if(!s.isEmpty() && s.charAt(0)=='0') { |
|
for(int i=1; i<s.length(); i++) { |
|
if(s.charAt(i)!='0') { |
|
return s.substring(i); |
|
} |
|
} |
|
return ""; |
|
} |
|
return s; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
static int getHexDigit(String s, int position) { |
|
int value = Character.digit(s.charAt(position), 16); |
|
if (value <= -1 || value >= 16) { |
|
throw new AssertionError("Unexpected failure of digit conversion of " + |
|
s.charAt(position)); |
|
} |
|
return value; |
|
} |
|
} |