Withdraw: Review: 4396272 - Parsing doubles fails to follow IEEE for largest decimal that should yield 0 (original) (raw)
Dmitry Nadezhin dmitry.nadezhin at gmail.com
Fri Feb 22 20:29:49 UTC 2013
- Previous message: Withdraw: Review: 4396272 - Parsing doubles fails to follow IEEE for largest decimal that should yield 0
- Next message: Withdraw: Review: 4396272 - Parsing doubles fails to follow IEEE for largest decimal that should yield 0
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Brian,
I removed unused methods and fields from FormattedFloatingDecimal. JDK build passes. The result of "hg diff" is attached.
-Dima
On Fri, Feb 22, 2013 at 9:49 PM, Brian Burkhalter <brian.burkhalter at oracle.com> wrote: > Dima, >> If the methods are definitely unused that would be correct. I suppose if a > clean build of the JDK does not complain then it is acceptable and correct. >> Thanks, >> Brian >> On Feb 22, 2013, at 9:41 AM, Dmitry Nadezhin wrote: >> So I think that the required change in FormattedFloatingDecimal is to > delete methods > doubleValue(), floatValue() and other unused methods and fields. Am I right > ? >>-------------- next part -------------- diff -r bb97c93e4fd7 src/share/classes/sun/misc/FormattedFloatingDecimal.java --- a/src/share/classes/sun/misc/FormattedFloatingDecimal.java Thu Feb 21 11:13:23 2013 -0800 +++ b/src/share/classes/sun/misc/FormattedFloatingDecimal.java Sat Feb 23 00:00:12 2013 +0400 @@ -25,10 +25,6 @@ package sun.misc; -import sun.misc.DoubleConsts; -import sun.misc.FloatConsts; -import java.util.regex.*;
public class FormattedFloatingDecimal{ boolean isExceptional; boolean isNegative; @@ -38,9 +34,6 @@ int nDigits; int bigIntExp; int bigIntNBits; - boolean mustSetRoundDir = false; - boolean fromHex = false; - int roundDir = 0; // set by doubleValue int precision; // number of digits to the right of decimal public enum Form { SCIENTIFIC, COMPATIBLE, DECIMAL_FLOAT, GENERAL }; @@ -72,10 +65,6 @@ static final long expOne = ((long)expBias)<<expShift; // exponent of 1.0 static final int maxSmallBinExp = 62; static final int minSmallBinExp = -( 63 / 3 ); - static final int maxDecimalDigits = 15; - static final int maxDecimalExponent = 308; - static final int minDecimalExponent = -324; - static final int bigDecimalExponent = 324; // i.e. abs(minDecimalExponent) static final long highbyte = 0xff00000000000000L; static final long highbit = 0x8000000000000000L; @@ -87,12 +76,6 @@ static final int singleExpShift = 23; static final int singleFractHOB = 1<<singleExpShift; static final int singleExpBias = 127; - static final int singleMaxDecimalDigits = 7; - static final int singleMaxDecimalExponent = 38; - static final int singleMinDecimalExponent = -45;
- static final int intDecimalDigits = 9;
/*
* count number of bits from high-order 1 bit to low-order 1 bit,
@@ -241,56 +224,6 @@ } /* - * Compute a number that is the ULP of the given value, - * for purposes of addition/subtraction. Generally easy. - * More difficult if subtracting and the argument - * is a normalized a power of 2, as the ULP changes at these points. - */ - private static double ulp( double dval, boolean subtracting ){ - long lbits = Double.doubleToLongBits( dval ) & ~signMask; - int binexp = (int)(lbits >>> expShift); - double ulpval; - if ( subtracting && ( binexp >= expShift ) && ((lbits&fractMask) == 0L) ){ - // for subtraction from normalized, powers of 2, - // use next-smaller exponent - binexp -= 1; - } - if ( binexp > expShift ){ - ulpval = Double.longBitsToDouble( ((long)(binexp-expShift))<<expShift ); - } else if ( binexp == 0 ){ - ulpval = Double.MIN_VALUE; - } else { - ulpval = Double.longBitsToDouble( 1L<<(binexp-1) ); - } - if ( subtracting ) ulpval = - ulpval;
return ulpval;
}
/*
* Round a double to a float.
* In addition to the fraction bits of the double,
* look at the class instance variable roundDir,
* which should help us avoid double-rounding error.
* roundDir was set in hardValueOf if the estimate was
* close enough, but not exact. It tells us which direction
* of rounding is preferred.
*/
float
stickyRound( double dval ){
long lbits = Double.doubleToLongBits( dval );
long binexp = lbits & expMask;
if ( binexp == 0L || binexp == expMask ){
// what we have here is special.
// don't worry, the right thing will happen.
return (float) dval;
}
lbits += (long)roundDir; // hack-o-matic.
return (float)Double.longBitsToDouble( lbits );
}
/*
- This is the easy subcase --
- all the significant bits, after scaling, are held in lvalue.
- negSign and decExponent tell us what processing and scaling @@ -1146,541 +1079,6 @@ } };
/*
* Take a FormattedFloatingDecimal, which we presumably just scanned in,
* and find out what its value is, as a double.
*
* AS A SIDE EFFECT, SET roundDir TO INDICATE PREFERRED
* ROUNDING DIRECTION in case the result is really destined
* for a single-precision float.
*/
public strictfp double doubleValue(){
int kDigits = Math.min( nDigits, maxDecimalDigits+1 );
long lValue;
double dValue;
double rValue, tValue;
// First, check for NaN and Infinity values
if(digits == infinity || digits == notANumber) {
if(digits == notANumber)
return Double.NaN;
else
return (isNegative?Double.NEGATIVE_INFINITY:Double.POSITIVE_INFINITY);
}
else {
if (mustSetRoundDir) {
roundDir = 0;
}
/*
* convert the lead kDigits to a long integer.
*/
// (special performance hack: start to do it using int)
int iValue = (int)digits[0]-(int)'0';
int iDigits = Math.min( kDigits, intDecimalDigits );
for ( int i=1; i < iDigits; i++ ){
iValue = iValue*10 + (int)digits[i]-(int)'0';
}
lValue = (long)iValue;
for ( int i=iDigits; i < kDigits; i++ ){
lValue = lValue*10L + (long)((int)digits[i]-(int)'0');
}
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 <= maxDecimalDigits ){
/*
* 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; // small floating integer
else if ( exp >= 0 ){
if ( exp <= maxSmallTen ){
/*
* Can get the answer with one operation,
* thus one roundoff.
*/
rValue = dValue * small10pow[exp];
if ( mustSetRoundDir ){
tValue = rValue / small10pow[exp];
roundDir = ( tValue == dValue ) ? 0
:( tValue < dValue ) ? 1
: -1;
}
return (isNegative)? -rValue : rValue;
}
int slop = maxDecimalDigits - kDigits;
if ( exp <= maxSmallTen+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 *= small10pow[slop];
rValue = dValue * small10pow[exp-slop];
if ( mustSetRoundDir ){
tValue = rValue / small10pow[exp-slop];
roundDir = ( tValue == dValue ) ? 0
:( tValue < dValue ) ? 1
: -1;
}
return (isNegative)? -rValue : rValue;
}
/*
* Else we have a hard case with a positive exp.
*/
} else {
if ( exp >= -maxSmallTen ){
/*
* Can get the answer in one division.
*/
rValue = dValue / small10pow[-exp];
tValue = rValue * small10pow[-exp];
if ( mustSetRoundDir ){
roundDir = ( tValue == dValue ) ? 0
:( tValue < dValue ) ? 1
: -1;
}
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 > maxDecimalExponent+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 *= small10pow[exp&15];
}
if ( (exp>>=4) != 0 ){
int j;
for( j = 0; exp > 1; j++, exp>>=1 ){
if ( (exp&1)!=0)
dValue *= big10pow[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 * big10pow[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 *= big10pow[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 < minDecimalExponent-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 /= small10pow[exp&15];
}
if ( (exp>>=4) != 0 ){
int j;
for( j = 0; exp > 1; j++, exp>>=1 ){
if ( (exp&1)!=0)
dValue *= tiny10pow[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 * tiny10pow[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 *= tiny10pow[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 FDBigInt arithmetic.
* Formulate the EXACT big-number result as
* bigD0 * 10^exp
*/
FDBigInt bigD0 = new FDBigInt( lValue, digits, kDigits, nDigits );
exp = decExponent - nDigits;
correctionLoop:
while(true){
/* AS A SIDE EFFECT, THIS METHOD WILL SET THE INSTANCE VARIABLES
* bigIntExp and bigIntNBits
*/
FDBigInt bigB = doubleToBigInt( dValue );
/*
* Scale bigD, bigB appropriately for
* big-integer operations.
* Naively, we multipy 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; // powers of 2, 5 in bigB
int D2, D5; // powers of 2, 5 in bigD
int Ulp2; // powers of 2 in halfUlp.
if ( exp >= 0 ){
B2 = B5 = 0;
D2 = D5 = exp;
} else {
B2 = B5 = -exp;
D2 = D5 = 0;
}
if ( bigIntExp >= 0 ){
B2 += bigIntExp;
} else {
D2 -= bigIntExp;
}
Ulp2 = B2;
// shift bigB and bigD left by a number s. t.
// halfUlp is still an integer.
int hulpbias;
if ( bigIntExp+bigIntNBits <= -expBias+1 ){
// This is going to be a denormalized number
// (if not actually zero).
// half an ULP is at 2^-(expBias+expShift+1)
hulpbias = bigIntExp+ expBias + expShift;
} else {
hulpbias = expShift + 2 - bigIntNBits;
}
B2 += hulpbias;
D2 += hulpbias;
// if there are common factors of 2, we might just as well
// factor them out, as they add nothing useful.
int common2 = Math.min( B2, Math.min( D2, Ulp2 ) );
B2 -= common2;
D2 -= common2;
Ulp2 -= common2;
// do multiplications by powers of 5 and 2
bigB = multPow52( bigB, B5, B2 );
FDBigInt bigD = multPow52( new FDBigInt( bigD0 ), D5, 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.
//
FDBigInt diff;
int cmpResult;
boolean overvalue;
if ( (cmpResult = bigB.cmp( bigD ) ) > 0 ){
overvalue = true; // our candidate is too big.
diff = bigB.sub( bigD );
if ( (bigIntNBits == 1) && (bigIntExp > -expBias) ){
// candidate is a normalized exact power of 2 and
// is too big. We will be subtracting.
// For our purposes, ulp is the ulp of the
// next smaller range.
Ulp2 -= 1;
if ( Ulp2 < 0 ){
// rats. Cannot de-scale ulp this far.
// must scale diff in other direction.
Ulp2 = 0;
diff.lshiftMe( 1 );
}
}
} else if ( cmpResult < 0 ){
overvalue = false; // our candidate is too small.
diff = bigD.sub( bigB );
} else {
// the candidate is exactly right!
// this happens with surprising fequency
break correctionLoop;
}
FDBigInt halfUlp = constructPow52( B5, Ulp2 );
if ( (cmpResult = diff.cmp( halfUlp ) ) < 0 ){
// difference is small.
// this is close enough
if (mustSetRoundDir) {
roundDir = overvalue ? -1 : 1;
}
break correctionLoop;
} else if ( cmpResult == 0 ){
// difference is exactly half an ULP
// round to some other value maybe, then finish
dValue += 0.5*ulp( dValue, overvalue );
// should check for bigIntNBits == 1 here??
if (mustSetRoundDir) {
roundDir = 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.
dValue += ulp( dValue, overvalue );
if ( dValue == 0.0 || dValue == Double.POSITIVE_INFINITY )
break correctionLoop; // oops. Fell off end of range.
continue; // try again.
}
}
return (isNegative)? -dValue : dValue;
}
}
/*
* Take a FormattedFloatingDecimal, which we presumably just scanned in,
* and find out what its value is, as a float.
* This is distinct from doubleValue() to avoid the extremely
* unlikely case of a double rounding error, wherein the converstion
* to double has one rounding error, and the conversion of that double
* to a float has another rounding error, IN THE WRONG DIRECTION,
* ( because of the preference to a zero low-order bit ).
*/
public strictfp float floatValue(){
int kDigits = Math.min( nDigits, singleMaxDecimalDigits+1 );
int iValue;
float fValue;
// First, check for NaN and Infinity values
if(digits == infinity || digits == notANumber) {
if(digits == notANumber)
return Float.NaN;
else
return (isNegative?Float.NEGATIVE_INFINITY:Float.POSITIVE_INFINITY);
}
else {
/*
* convert the lead kDigits to an integer.
*/
iValue = (int)digits[0]-(int)'0';
for ( int i=1; i < kDigits; i++ ){
iValue = iValue*10 + (int)digits[i]-(int)'0';
}
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 <= singleMaxDecimalDigits ){
/*
* 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; // small floating integer
else if ( exp >= 0 ){
if ( exp <= singleMaxSmallTen ){
/*
* Can get the answer with one operation,
* thus one roundoff.
*/
fValue *= singleSmall10pow[exp];
return (isNegative)? -fValue : fValue;
}
int slop = singleMaxDecimalDigits - kDigits;
if ( exp <= singleMaxSmallTen+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.
*/
fValue *= singleSmall10pow[slop];
fValue *= singleSmall10pow[exp-slop];
return (isNegative)? -fValue : fValue;
}
/*
* Else we have a hard case with a positive exp.
*/
} else {
if ( exp >= -singleMaxSmallTen ){
/*
* Can get the answer in one division.
*/
fValue /= singleSmall10pow[-exp];
return (isNegative)? -fValue : fValue;
}
/*
* Else we have a hard case with a negative exp.
*/
}
} else if ( (decExponent >= nDigits) && (nDigits+decExponent <= maxDecimalDigits) ){
/*
* 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 *= small10pow[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 weeding out obviously out-of-range
* results, then convert to double and go to
* common hard-case code.
*/
if ( decExponent > singleMaxDecimalExponent+1 ){
/*
* Lets face it. This is going to be
* Infinity. Cut to the chase.
*/
return (isNegative)? Float.NEGATIVE_INFINITY : Float.POSITIVE_INFINITY;
} else if ( decExponent < singleMinDecimalExponent-1 ){
/*
* Lets face it. This is going to be
* zero. Cut to the chase.
*/
return (isNegative)? -0.0f : 0.0f;
}
/*
* Here, we do 'way too much work, but throwing away
* our partial results, and going and doing the whole
* thing as double, then throwing away half the bits that computes
* when we convert back to float.
*
* The alternative is to reproduce the whole multiple-precision
* algorythm for float precision, or to try to parameterize it
* for common usage. The former will take about 400 lines of code,
* and the latter I tried without success. Thus the semi-hack
* answer here.
*/
mustSetRoundDir = !fromHex;
double dValue = doubleValue();
return stickyRound( dValue );
}
}
/*
* All the positive powers of 10 that can be
* represented exactly in double/float.
*/
private static final double small10pow[] = {
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 singleSmall10pow[] = {
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 big10pow[] = {
1e16, 1e32, 1e64, 1e128, 1e256 };
private static final double tiny10pow[] = {
1e-16, 1e-32, 1e-64, 1e-128, 1e-256 };
private static final int maxSmallTen = small10pow.length-1;
private static final int singleMaxSmallTen = singleSmall10pow.length-1;
private static final int small5pow[] = { 1, 5,
- Previous message: Withdraw: Review: 4396272 - Parsing doubles fails to follow IEEE for largest decimal that should yield 0
- Next message: Withdraw: Review: 4396272 - Parsing doubles fails to follow IEEE for largest decimal that should yield 0
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]