7032154: Performance tuning of sun.misc.FloatingDecimal/FormattedFloatingDecimal
Summary: Performance improvements for double/float -> String and decimal/hex String -> double/float conversions.
Reviewed-by: martin, iris
Contributed-by: Sergey Kuksenko <sergey.kuksenko@oracle.com>, Brian Burkhalter <brian.burkhalter@oracle.com>, Dmitry Nadezhin <dmitry.nadezhin@oracle.com>, Olivier Lagneau <olivier.lagneau@oracle.com>
--- a/jdk/src/share/classes/java/lang/AbstractStringBuilder.java Thu Jun 06 11:39:34 2013 -0700
+++ b/jdk/src/share/classes/java/lang/AbstractStringBuilder.java Wed Jun 05 21:01:02 2013 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -689,7 +689,7 @@
* @return a reference to this object.
*/
public AbstractStringBuilder append(float f) {
- new FloatingDecimal(f).appendTo(this);
+ FloatingDecimal.appendTo(f,this);
return this;
}
@@ -706,7 +706,7 @@
* @return a reference to this object.
*/
public AbstractStringBuilder append(double d) {
- new FloatingDecimal(d).appendTo(this);
+ FloatingDecimal.appendTo(d,this);
return this;
}
--- a/jdk/src/share/classes/java/lang/Double.java Thu Jun 06 11:39:34 2013 -0700
+++ b/jdk/src/share/classes/java/lang/Double.java Wed Jun 05 21:01:02 2013 -0700
@@ -201,7 +201,7 @@
* @return a string representation of the argument.
*/
public static String toString(double d) {
- return new FloatingDecimal(d).toJavaFormatString();
+ return FloatingDecimal.toJavaFormatString(d);
}
/**
@@ -509,7 +509,7 @@
* parsable number.
*/
public static Double valueOf(String s) throws NumberFormatException {
- return new Double(FloatingDecimal.readJavaFormatString(s).doubleValue());
+ return new Double(parseDouble(s));
}
/**
@@ -545,7 +545,7 @@
* @since 1.2
*/
public static double parseDouble(String s) throws NumberFormatException {
- return FloatingDecimal.readJavaFormatString(s).doubleValue();
+ return FloatingDecimal.parseDouble(s);
}
/**
--- a/jdk/src/share/classes/java/lang/Float.java Thu Jun 06 11:39:34 2013 -0700
+++ b/jdk/src/share/classes/java/lang/Float.java Wed Jun 05 21:01:02 2013 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -203,7 +203,7 @@
* @return a string representation of the argument.
*/
public static String toString(float f) {
- return new FloatingDecimal(f).toJavaFormatString();
+ return FloatingDecimal.toJavaFormatString(f);
}
/**
@@ -421,7 +421,7 @@
* parsable number.
*/
public static Float valueOf(String s) throws NumberFormatException {
- return new Float(FloatingDecimal.readJavaFormatString(s).floatValue());
+ return new Float(parseFloat(s));
}
/**
@@ -456,7 +456,7 @@
* @since 1.2
*/
public static float parseFloat(String s) throws NumberFormatException {
- return FloatingDecimal.readJavaFormatString(s).floatValue();
+ return FloatingDecimal.parseFloat(s);
}
/**
--- a/jdk/src/share/classes/java/text/DigitList.java Thu Jun 06 11:39:34 2013 -0700
+++ b/jdk/src/share/classes/java/text/DigitList.java Wed Jun 05 21:01:02 2013 -0700
@@ -271,7 +271,7 @@
* @param maximumFractionDigits The most fractional digits which should
* be converted.
*/
- public final void set(boolean isNegative, double source, int maximumFractionDigits) {
+ final void set(boolean isNegative, double source, int maximumFractionDigits) {
set(isNegative, source, maximumFractionDigits, true);
}
@@ -288,10 +288,11 @@
*/
final void set(boolean isNegative, double source, int maximumDigits, boolean fixedPoint) {
- FloatingDecimal fd = new FloatingDecimal(source);
- boolean hasBeenRoundedUp = fd.digitsRoundedUp();
- boolean allDecimalDigits = fd.decimalDigitsExact();
- String digitsString = fd.toJavaFormatString();
+ FloatingDecimal.BinaryToASCIIConverter fdConverter = FloatingDecimal.getBinaryToASCIIConverter(source);
+ boolean hasBeenRoundedUp = fdConverter.digitsRoundedUp();
+ boolean allDecimalDigits = fdConverter.decimalDigitsExact();
+ assert !fdConverter.isExceptional();
+ String digitsString = fdConverter.toJavaFormatString();
set(isNegative, digitsString,
hasBeenRoundedUp, allDecimalDigits,
@@ -305,9 +306,9 @@
* @param allDecimalDigits Boolean value indicating if the digits in s are
* an exact decimal representation of the double that was passed.
*/
- final void set(boolean isNegative, String s,
- boolean roundedUp, boolean allDecimalDigits,
- int maximumDigits, boolean fixedPoint) {
+ private void set(boolean isNegative, String s,
+ boolean roundedUp, boolean allDecimalDigits,
+ int maximumDigits, boolean fixedPoint) {
this.isNegative = isNegative;
int len = s.length();
char[] source = getDataChars(len);
@@ -607,7 +608,7 @@
/**
* Utility routine to set the value of the digit list from a long
*/
- public final void set(boolean isNegative, long source) {
+ final void set(boolean isNegative, long source) {
set(isNegative, source, 0);
}
@@ -620,7 +621,7 @@
* If maximumDigits is lower than the number of significant digits
* in source, the representation will be rounded. Ignored if <= 0.
*/
- public final void set(boolean isNegative, long source, int maximumDigits) {
+ final void set(boolean isNegative, long source, int maximumDigits) {
this.isNegative = isNegative;
// This method does not expect a negative number. However,
--- a/jdk/src/share/classes/java/util/Formatter.java Thu Jun 06 11:39:34 2013 -0700
+++ b/jdk/src/share/classes/java/util/Formatter.java Wed Jun 05 21:01:02 2013 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -2807,10 +2807,10 @@
cal = Calendar.getInstance(l == null ? Locale.US : l);
cal.setTime((Date)arg);
} else if (arg instanceof Calendar) {
- cal = (Calendar) ((Calendar)arg).clone();
+ cal = (Calendar) ((Calendar) arg).clone();
cal.setLenient(true);
} else if (arg instanceof TemporalAccessor) {
- print((TemporalAccessor)arg, c, l);
+ print((TemporalAccessor) arg, c, l);
return;
} else {
failConversion(c, arg);
@@ -3242,13 +3242,10 @@
int prec = (precision == -1 ? 6 : precision);
FormattedFloatingDecimal fd
- = new FormattedFloatingDecimal(value, prec,
- FormattedFloatingDecimal.Form.SCIENTIFIC);
-
- char[] v = new char[MAX_FD_CHARS];
- int len = fd.getChars(v);
-
- char[] mant = addZeros(mantissa(v, len), prec);
+ = FormattedFloatingDecimal.valueOf(value, prec,
+ FormattedFloatingDecimal.Form.SCIENTIFIC);
+
+ char[] mant = addZeros(fd.getMantissa(), prec);
// If the precision is zero and the '#' flag is set, add the
// requested decimal point.
@@ -3256,7 +3253,7 @@
mant = addDot(mant);
char[] exp = (value == 0.0)
- ? new char[] {'+','0','0'} : exponent(v, len);
+ ? new char[] {'+','0','0'} : fd.getExponent();
int newW = width;
if (width != -1)
@@ -3279,15 +3276,10 @@
int prec = (precision == -1 ? 6 : precision);
FormattedFloatingDecimal fd
- = new FormattedFloatingDecimal(value, prec,
- FormattedFloatingDecimal.Form.DECIMAL_FLOAT);
-
- // MAX_FD_CHARS + 1 (round?)
- char[] v = new char[MAX_FD_CHARS + 1
- + Math.abs(fd.getExponent())];
- int len = fd.getChars(v);
-
- char[] mant = addZeros(mantissa(v, len), prec);
+ = FormattedFloatingDecimal.valueOf(value, prec,
+ FormattedFloatingDecimal.Form.DECIMAL_FLOAT);
+
+ char[] mant = addZeros(fd.getMantissa(), prec);
// If the precision is zero and the '#' flag is set, add the
// requested decimal point.
@@ -3306,22 +3298,17 @@
prec = 1;
FormattedFloatingDecimal fd
- = new FormattedFloatingDecimal(value, prec,
- FormattedFloatingDecimal.Form.GENERAL);
-
- // MAX_FD_CHARS + 1 (round?)
- char[] v = new char[MAX_FD_CHARS + 1
- + Math.abs(fd.getExponent())];
- int len = fd.getChars(v);
-
- char[] exp = exponent(v, len);
+ = FormattedFloatingDecimal.valueOf(value, prec,
+ FormattedFloatingDecimal.Form.GENERAL);
+
+ char[] exp = fd.getExponent();
if (exp != null) {
prec -= 1;
} else {
prec = prec - (value == 0 ? 0 : fd.getExponentRounded()) - 1;
}
- char[] mant = addZeros(mantissa(v, len), prec);
+ char[] mant = addZeros(fd.getMantissa(), prec);
// If the precision is zero and the '#' flag is set, add the
// requested decimal point.
if (f.contains(Flags.ALTERNATE) && (prec == 0))
@@ -3380,30 +3367,6 @@
}
}
- private char[] mantissa(char[] v, int len) {
- int i;
- for (i = 0; i < len; i++) {
- if (v[i] == 'e')
- break;
- }
- char[] tmp = new char[i];
- System.arraycopy(v, 0, tmp, 0, i);
- return tmp;
- }
-
- private char[] exponent(char[] v, int len) {
- int i;
- for (i = len - 1; i >= 0; i--) {
- if (v[i] == 'e')
- break;
- }
- if (i == -1)
- return null;
- char[] tmp = new char[len - i - 1];
- System.arraycopy(v, i + 1, tmp, 0, len - i - 1);
- return tmp;
- }
-
// Add zeros to the requested precision.
private char[] addZeros(char[] v, int prec) {
// Look for the dot. If we don't find one, the we'll need to add
--- a/jdk/src/share/classes/sun/misc/FDBigInt.java Thu Jun 06 11:39:34 2013 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,493 +0,0 @@
-/*
- * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.misc;
-
-/*
- * A really, really simple bigint package
- * tailored to the needs of floating base conversion.
- */
-class FDBigInt {
- int nWords; // number of words used
- int data[]; // value: data[0] is least significant
-
-
- public FDBigInt( int v ){
- nWords = 1;
- data = new int[1];
- data[0] = v;
- }
-
- public FDBigInt( long v ){
- data = new int[2];
- data[0] = (int)v;
- data[1] = (int)(v>>>32);
- nWords = (data[1]==0) ? 1 : 2;
- }
-
- public FDBigInt( FDBigInt other ){
- data = new int[nWords = other.nWords];
- System.arraycopy( other.data, 0, data, 0, nWords );
- }
-
- private FDBigInt( int [] d, int n ){
- data = d;
- nWords = n;
- }
-
- public FDBigInt( long seed, char digit[], int nd0, int nd ){
- int n= (nd+8)/9; // estimate size needed.
- if ( n < 2 ) n = 2;
- data = new int[n]; // allocate enough space
- data[0] = (int)seed; // starting value
- data[1] = (int)(seed>>>32);
- nWords = (data[1]==0) ? 1 : 2;
- int i = nd0;
- int limit = nd-5; // slurp digits 5 at a time.
- int v;
- while ( i < limit ){
- int ilim = i+5;
- v = (int)digit[i++]-(int)'0';
- while( i <ilim ){
- v = 10*v + (int)digit[i++]-(int)'0';
- }
- multaddMe( 100000, v); // ... where 100000 is 10^5.
- }
- int factor = 1;
- v = 0;
- while ( i < nd ){
- v = 10*v + (int)digit[i++]-(int)'0';
- factor *= 10;
- }
- if ( factor != 1 ){
- multaddMe( factor, v );
- }
- }
-
- /*
- * Left shift by c bits.
- * Shifts this in place.
- */
- public void
- lshiftMe( int c )throws IllegalArgumentException {
- if ( c <= 0 ){
- if ( c == 0 )
- return; // silly.
- else
- throw new IllegalArgumentException("negative shift count");
- }
- int wordcount = c>>5;
- int bitcount = c & 0x1f;
- int anticount = 32-bitcount;
- int t[] = data;
- int s[] = data;
- if ( nWords+wordcount+1 > t.length ){
- // reallocate.
- t = new int[ nWords+wordcount+1 ];
- }
- int target = nWords+wordcount;
- int src = nWords-1;
- if ( bitcount == 0 ){
- // special hack, since an anticount of 32 won't go!
- System.arraycopy( s, 0, t, wordcount, nWords );
- target = wordcount-1;
- } else {
- t[target--] = s[src]>>>anticount;
- while ( src >= 1 ){
- t[target--] = (s[src]<<bitcount) | (s[--src]>>>anticount);
- }
- t[target--] = s[src]<<bitcount;
- }
- while( target >= 0 ){
- t[target--] = 0;
- }
- data = t;
- nWords += wordcount + 1;
- // may have constructed high-order word of 0.
- // if so, trim it
- while ( nWords > 1 && data[nWords-1] == 0 )
- nWords--;
- }
-
- /*
- * normalize this number by shifting until
- * the MSB of the number is at 0x08000000.
- * This is in preparation for quoRemIteration, below.
- * The idea is that, to make division easier, we want the
- * divisor to be "normalized" -- usually this means shifting
- * the MSB into the high words sign bit. But because we know that
- * the quotient will be 0 < q < 10, we would like to arrange that
- * the dividend not span up into another word of precision.
- * (This needs to be explained more clearly!)
- */
- public int
- normalizeMe() throws IllegalArgumentException {
- int src;
- int wordcount = 0;
- int bitcount = 0;
- int v = 0;
- for ( src= nWords-1 ; src >= 0 && (v=data[src]) == 0 ; src--){
- wordcount += 1;
- }
- if ( src < 0 ){
- // oops. Value is zero. Cannot normalize it!
- throw new IllegalArgumentException("zero value");
- }
- /*
- * In most cases, we assume that wordcount is zero. This only
- * makes sense, as we try not to maintain any high-order
- * words full of zeros. In fact, if there are zeros, we will
- * simply SHORTEN our number at this point. Watch closely...
- */
- nWords -= wordcount;
- /*
- * Compute how far left we have to shift v s.t. its highest-
- * order bit is in the right place. Then call lshiftMe to
- * do the work.
- */
- if ( (v & 0xf0000000) != 0 ){
- // will have to shift up into the next word.
- // too bad.
- for( bitcount = 32 ; (v & 0xf0000000) != 0 ; bitcount-- )
- v >>>= 1;
- } else {
- while ( v <= 0x000fffff ){
- // hack: byte-at-a-time shifting
- v <<= 8;
- bitcount += 8;
- }
- while ( v <= 0x07ffffff ){
- v <<= 1;
- bitcount += 1;
- }
- }
- if ( bitcount != 0 )
- lshiftMe( bitcount );
- return bitcount;
- }
-
- /*
- * Multiply a FDBigInt by an int.
- * Result is a new FDBigInt.
- */
- public FDBigInt
- mult( int iv ) {
- long v = iv;
- int r[];
- long p;
-
- // guess adequate size of r.
- r = new int[ ( v * ((long)data[nWords-1]&0xffffffffL) > 0xfffffffL ) ? nWords+1 : nWords ];
- p = 0L;
- for( int i=0; i < nWords; i++ ) {
- p += v * ((long)data[i]&0xffffffffL);
- r[i] = (int)p;
- p >>>= 32;
- }
- if ( p == 0L){
- return new FDBigInt( r, nWords );
- } else {
- r[nWords] = (int)p;
- return new FDBigInt( r, nWords+1 );
- }
- }
-
- /*
- * Multiply a FDBigInt by an int and add another int.
- * Result is computed in place.
- * Hope it fits!
- */
- public void
- multaddMe( int iv, int addend ) {
- long v = iv;
- long p;
-
- // unroll 0th iteration, doing addition.
- p = v * ((long)data[0]&0xffffffffL) + ((long)addend&0xffffffffL);
- data[0] = (int)p;
- p >>>= 32;
- for( int i=1; i < nWords; i++ ) {
- p += v * ((long)data[i]&0xffffffffL);
- data[i] = (int)p;
- p >>>= 32;
- }
- if ( p != 0L){
- data[nWords] = (int)p; // will fail noisily if illegal!
- nWords++;
- }
- }
-
- /*
- * Multiply a FDBigInt by another FDBigInt.
- * Result is a new FDBigInt.
- */
- public FDBigInt
- mult( FDBigInt other ){
- // crudely guess adequate size for r
- int r[] = new int[ nWords + other.nWords ];
- int i;
- // I think I am promised zeros...
-
- for( i = 0; i < this.nWords; i++ ){
- long v = (long)this.data[i] & 0xffffffffL; // UNSIGNED CONVERSION
- long p = 0L;
- int j;
- for( j = 0; j < other.nWords; j++ ){
- p += ((long)r[i+j]&0xffffffffL) + v*((long)other.data[j]&0xffffffffL); // UNSIGNED CONVERSIONS ALL 'ROUND.
- r[i+j] = (int)p;
- p >>>= 32;
- }
- r[i+j] = (int)p;
- }
- // compute how much of r we actually needed for all that.
- for ( i = r.length-1; i> 0; i--)
- if ( r[i] != 0 )
- break;
- return new FDBigInt( r, i+1 );
- }
-
- /*
- * Add one FDBigInt to another. Return a FDBigInt
- */
- public FDBigInt
- add( FDBigInt other ){
- int i;
- int a[], b[];
- int n, m;
- long c = 0L;
- // arrange such that a.nWords >= b.nWords;
- // n = a.nWords, m = b.nWords
- if ( this.nWords >= other.nWords ){
- a = this.data;
- n = this.nWords;
- b = other.data;
- m = other.nWords;
- } else {
- a = other.data;
- n = other.nWords;
- b = this.data;
- m = this.nWords;
- }
- int r[] = new int[ n ];
- for ( i = 0; i < n; i++ ){
- c += (long)a[i] & 0xffffffffL;
- if ( i < m ){
- c += (long)b[i] & 0xffffffffL;
- }
- r[i] = (int) c;
- c >>= 32; // signed shift.
- }
- if ( c != 0L ){
- // oops -- carry out -- need longer result.
- int s[] = new int[ r.length+1 ];
- System.arraycopy( r, 0, s, 0, r.length );
- s[i++] = (int)c;
- return new FDBigInt( s, i );
- }
- return new FDBigInt( r, i );
- }
-
- /*
- * Subtract one FDBigInt from another. Return a FDBigInt
- * Assert that the result is positive.
- */
- public FDBigInt
- sub( FDBigInt other ){
- int r[] = new int[ this.nWords ];
- int i;
- int n = this.nWords;
- int m = other.nWords;
- int nzeros = 0;
- long c = 0L;
- for ( i = 0; i < n; i++ ){
- c += (long)this.data[i] & 0xffffffffL;
- if ( i < m ){
- c -= (long)other.data[i] & 0xffffffffL;
- }
- if ( ( r[i] = (int) c ) == 0 )
- nzeros++;
- else
- nzeros = 0;
- c >>= 32; // signed shift
- }
- assert c == 0L : c; // borrow out of subtract
- assert dataInRangeIsZero(i, m, other); // negative result of subtract
- return new FDBigInt( r, n-nzeros );
- }
-
- private static boolean dataInRangeIsZero(int i, int m, FDBigInt other) {
- while ( i < m )
- if (other.data[i++] != 0)
- return false;
- return true;
- }
-
- /*
- * Compare FDBigInt with another FDBigInt. Return an integer
- * >0: this > other
- * 0: this == other
- * <0: this < other
- */
- public int
- cmp( FDBigInt other ){
- int i;
- if ( this.nWords > other.nWords ){
- // if any of my high-order words is non-zero,
- // then the answer is evident
- int j = other.nWords-1;
- for ( i = this.nWords-1; i > j ; i-- )
- if ( this.data[i] != 0 ) return 1;
- }else if ( this.nWords < other.nWords ){
- // if any of other's high-order words is non-zero,
- // then the answer is evident
- int j = this.nWords-1;
- for ( i = other.nWords-1; i > j ; i-- )
- if ( other.data[i] != 0 ) return -1;
- } else{
- i = this.nWords-1;
- }
- for ( ; i > 0 ; i-- )
- if ( this.data[i] != other.data[i] )
- break;
- // careful! want unsigned compare!
- // use brute force here.
- int a = this.data[i];
- int b = other.data[i];
- if ( a < 0 ){
- // a is really big, unsigned
- if ( b < 0 ){
- return a-b; // both big, negative
- } else {
- return 1; // b not big, answer is obvious;
- }
- } else {
- // a is not really big
- if ( b < 0 ) {
- // but b is really big
- return -1;
- } else {
- return a - b;
- }
- }
- }
-
- /*
- * Compute
- * q = (int)( this / S )
- * this = 10 * ( this mod S )
- * Return q.
- * This is the iteration step of digit development for output.
- * We assume that S has been normalized, as above, and that
- * "this" has been lshift'ed accordingly.
- * Also assume, of course, that the result, q, can be expressed
- * as an integer, 0 <= q < 10.
- */
- public int
- quoRemIteration( FDBigInt S )throws IllegalArgumentException {
- // ensure that this and S have the same number of
- // digits. If S is properly normalized and q < 10 then
- // this must be so.
- if ( nWords != S.nWords ){
- throw new IllegalArgumentException("disparate values");
- }
- // estimate q the obvious way. We will usually be
- // right. If not, then we're only off by a little and
- // will re-add.
- int n = nWords-1;
- long q = ((long)data[n]&0xffffffffL) / (long)S.data[n];
- long diff = 0L;
- for ( int i = 0; i <= n ; i++ ){
- diff += ((long)data[i]&0xffffffffL) - q*((long)S.data[i]&0xffffffffL);
- data[i] = (int)diff;
- diff >>= 32; // N.B. SIGNED shift.
- }
- if ( diff != 0L ) {
- // damn, damn, damn. q is too big.
- // add S back in until this turns +. This should
- // not be very many times!
- long sum = 0L;
- while ( sum == 0L ){
- sum = 0L;
- for ( int i = 0; i <= n; i++ ){
- sum += ((long)data[i]&0xffffffffL) + ((long)S.data[i]&0xffffffffL);
- data[i] = (int) sum;
- sum >>= 32; // Signed or unsigned, answer is 0 or 1
- }
- /*
- * Originally the following line read
- * "if ( sum !=0 && sum != -1 )"
- * but that would be wrong, because of the
- * treatment of the two values as entirely unsigned,
- * it would be impossible for a carry-out to be interpreted
- * as -1 -- it would have to be a single-bit carry-out, or
- * +1.
- */
- assert sum == 0 || sum == 1 : sum; // carry out of division correction
- q -= 1;
- }
- }
- // finally, we can multiply this by 10.
- // it cannot overflow, right, as the high-order word has
- // at least 4 high-order zeros!
- long p = 0L;
- for ( int i = 0; i <= n; i++ ){
- p += 10*((long)data[i]&0xffffffffL);
- data[i] = (int)p;
- p >>= 32; // SIGNED shift.
- }
- assert p == 0L : p; // Carry out of *10
- return (int)q;
- }
-
- public long
- longValue(){
- // if this can be represented as a long, return the value
- assert this.nWords > 0 : this.nWords; // longValue confused
-
- if (this.nWords == 1)
- return ((long)data[0]&0xffffffffL);
-
- assert dataInRangeIsZero(2, this.nWords, this); // value too big
- assert data[1] >= 0; // value too big
- return ((long)(data[1]) << 32) | ((long)data[0]&0xffffffffL);
- }
-
- public String
- toString() {
- StringBuffer r = new StringBuffer(30);
- r.append('[');
- int i = Math.min( nWords-1, data.length-1) ;
- if ( nWords > data.length ){
- r.append( "("+data.length+"<"+nWords+"!)" );
- }
- for( ; i> 0 ; i-- ){
- r.append( Integer.toHexString( data[i] ) );
- r.append(' ');
- }
- r.append( Integer.toHexString( data[0] ) );
- r.append(']');
- return new String( r );
- }
-}
--- a/jdk/src/share/classes/sun/misc/FloatingDecimal.java Thu Jun 06 11:39:34 2013 -0700
+++ b/jdk/src/share/classes/sun/misc/FloatingDecimal.java Wed Jun 05 21:01:02 2013 -0700
@@ -25,602 +25,785 @@
package sun.misc;
-import sun.misc.DoubleConsts;
-import sun.misc.FloatConsts;
+import java.util.Arrays;
import java.util.regex.*;
+/**
+ * A class for converting between ASCII and decimal representations of a single
+ * or double precision floating point number. Most conversions are provided via
+ * static convenience methods, although a <code>BinaryToASCIIConverter</code>
+ * instance may be obtained and reused.
+ */
public class FloatingDecimal{
- boolean isExceptional;
- boolean isNegative;
- int decExponent;
- char digits[];
- int nDigits;
- int bigIntExp;
- int bigIntNBits;
- boolean mustSetRoundDir = false;
- boolean fromHex = false;
- int roundDir = 0; // set by doubleValue
+ //
+ // 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 ); // assumed High-Order bit
+ static final long EXP_ONE = ((long)DoubleConsts.EXP_BIAS)<<EXP_SHIFT; // exponent of 1.0
+ 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; // i.e. abs(MIN_DECIMAL_EXPONENT)
+
+ 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 INT_DECIMAL_DIGITS = 9;
+
+ /**
+ * Converts a double precision floating point value to a <code>String</code>.
+ *
+ * @param d The double precision value.
+ * @return The value converted to a <code>String</code>.
+ */
+ public static String toJavaFormatString(double d) {
+ return getBinaryToASCIIConverter(d).toJavaFormatString();
+ }
- /*
- * The fields below provides 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.
+ /**
+ * Converts a single precision floating point value to a <code>String</code>.
+ *
+ * @param f The single precision value.
+ * @return The value converted to a <code>String</code>.
*/
+ public static String toJavaFormatString(float f) {
+ return getBinaryToASCIIConverter(f).toJavaFormatString();
+ }
- // True if the dtoa() binary to decimal conversion was exact.
- boolean exactDecimalConversion = false;
+ /**
+ * Appends a double precision floating point value to an <code>Appendable</code>.
+ * @param d The double precision value.
+ * @param buf The <code>Appendable</code> with the value appended.
+ */
+ public static void appendTo(double d, Appendable buf) {
+ getBinaryToASCIIConverter(d).appendTo(buf);
+ }
- // True if the result of the binary to decimal conversion was rounded-up
- // at the end of the conversion process, i.e. roundUp() method was called.
- boolean decimalDigitsRoundedUp = false;
+ /**
+ * Appends a single precision floating point value to an <code>Appendable</code>.
+ * @param f The single precision value.
+ * @param buf The <code>Appendable</code> with the value appended.
+ */
+ public static void appendTo(float f, Appendable buf) {
+ getBinaryToASCIIConverter(f).appendTo(buf);
+ }
- private FloatingDecimal( boolean negSign, int decExponent, char []digits, int n, boolean e )
- {
- isNegative = negSign;
- isExceptional = e;
- this.decExponent = decExponent;
- this.digits = digits;
- this.nDigits = n;
+ /**
+ * Converts a <code>String</code> to a double precision floating point value.
+ *
+ * @param s The <code>String</code> to convert.
+ * @return The double precision value.
+ * @throws NumberFormatException If the <code>String</code> does not
+ * represent a properly formatted double precision value.
+ */
+ public static double parseDouble(String s) throws NumberFormatException {
+ return readJavaFormatString(s).doubleValue();
+ }
+
+ /**
+ * Converts a <code>String</code> to a single precision floating point value.
+ *
+ * @param s The <code>String</code> to convert.
+ * @return The single precision value.
+ * @throws NumberFormatException If the <code>String</code> does not
+ * represent a properly formatted single precision value.
+ */
+ public static float parseFloat(String s) throws NumberFormatException {
+ return readJavaFormatString(s).floatValue();
}
- /*
- * Constants of the implementation
- * Most are IEEE-754 related.
- * (There are more really boring constants at the end.)
+ /**
+ * A converter which can process single or double precision floating point
+ * values into an ASCII <code>String</code> representation.
*/
- static final long signMask = 0x8000000000000000L;
- static final long expMask = 0x7ff0000000000000L;
- static final long fractMask= ~(signMask|expMask);
- static final int expShift = 52;
- static final int expBias = 1023;
- static final long fractHOB = ( 1L<<expShift ); // assumed High-Order bit
- 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)
+ public interface BinaryToASCIIConverter {
+ /**
+ * Converts a floating point value into an ASCII <code>String</code>.
+ * @return The value converted to a <code>String</code>.
+ */
+ public String toJavaFormatString();
+
+ /**
+ * Appends a floating point value to an <code>Appendable</code>.
+ * @param buf The <code>Appendable</code> to receive the value.
+ */
+ public void appendTo(Appendable buf);
- static final long highbyte = 0xff00000000000000L;
- static final long highbit = 0x8000000000000000L;
- static final long lowbytes = ~highbyte;
+ /**
+ * Retrieves the decimal exponent most closely corresponding to this value.
+ * @return The decimal exponent.
+ */
+ public int getDecimalExponent();
+
+ /**
+ * Retrieves the value as an array of digits.
+ * @param digits The digit array.
+ * @return The number of valid digits copied into the array.
+ */
+ public int getDigits(char[] digits);
+
+ /**
+ * Indicates the sign of the value.
+ * @return <code>value < 0.0</code>.
+ */
+ public boolean isNegative();
- static final int singleSignMask = 0x80000000;
- static final int singleExpMask = 0x7f800000;
- static final int singleFractMask = ~(singleSignMask|singleExpMask);
- 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;
+ /**
+ * Indicates whether the value is either infinite or not a number.
+ *
+ * @return <code>true</code> if and only if the value is <code>NaN</code>
+ * or infinite.
+ */
+ public boolean isExceptional();
- static final int intDecimalDigits = 9;
-
+ /**
+ * Indicates whether the value was rounded up during the binary to ASCII
+ * conversion.
+ *
+ * @return <code>true</code> if and only if the value was rounded up.
+ */
+ public boolean digitsRoundedUp();
- /*
- * count number of bits from high-order 1 bit to low-order 1 bit,
- * inclusive.
+ /**
+ * Indicates whether the binary to ASCII conversion was exact.
+ *
+ * @return <code>true</code> if any only if the conversion was exact.
+ */
+ public boolean decimalDigitsExact();
+ }
+
+ /**
+ * A <code>BinaryToASCIIConverter</code> which represents <code>NaN</code>
+ * and infinite values.
*/
- private static int
- countBits( long v ){
- //
- // the strategy is to shift until we get a non-zero sign bit
- // then shift until we have no bits left, counting the difference.
- // we do byte shifting as a hack. Hope it helps.
- //
- if ( v == 0L ) return 0;
+ private static class ExceptionalBinaryToASCIIBuffer implements BinaryToASCIIConverter {
+ final private String image;
+ private boolean isNegative;
- while ( ( v & highbyte ) == 0L ){
- v <<= 8;
- }
- while ( v > 0L ) { // i.e. while ((v&highbit) == 0L )
- v <<= 1;
+ public ExceptionalBinaryToASCIIBuffer(String image, boolean isNegative) {
+ this.image = image;
+ this.isNegative = isNegative;
}
- int n = 0;
- while (( v & lowbytes ) != 0L ){
- v <<= 8;
- n += 8;
+ @Override
+ public String toJavaFormatString() {
+ return image;
}
- while ( v != 0L ){
- v <<= 1;
- n += 1;
- }
- return n;
- }
- /*
- * Keep big powers of 5 handy for future reference.
- */
- private static FDBigInt b5p[];
+ @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;
+ }
+ }
- private static synchronized FDBigInt
- big5pow( int p ){
- assert p >= 0 : p; // negative power of 5
- if ( b5p == null ){
- b5p = new FDBigInt[ p+1 ];
- }else if (b5p.length <= p ){
- FDBigInt t[] = new FDBigInt[ p+1 ];
- System.arraycopy( b5p, 0, t, 0, b5p.length );
- b5p = t;
+ @Override
+ public int getDecimalExponent() {
+ throw new IllegalArgumentException("Exceptional value does not have an exponent");
}
- if ( b5p[p] != null )
- return b5p[p];
- else if ( p < small5pow.length )
- return b5p[p] = new FDBigInt( small5pow[p] );
- else if ( p < long5pow.length )
- return b5p[p] = new FDBigInt( long5pow[p] );
- else {
- // construct the value.
- // recursively.
- int q, r;
- // in order to compute 5^p,
- // compute its square root, 5^(p/2) and square.
- // or, let q = p / 2, r = p -q, then
- // 5^p = 5^(q+r) = 5^q * 5^r
- q = p >> 1;
- r = p - q;
- FDBigInt bigq = b5p[q];
- if ( bigq == null )
- bigq = big5pow ( q );
- if ( r < small5pow.length ){
- return (b5p[p] = bigq.mult( small5pow[r] ) );
- }else{
- FDBigInt bigr = b5p[ r ];
- if ( bigr == null )
- bigr = big5pow( r );
- return (b5p[p] = bigq.mult( bigr ) );
- }
+
+ @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");
}
}
- //
- // a common operation
- //
- private static FDBigInt
- multPow52( FDBigInt v, int p5, int p2 ){
- if ( p5 != 0 ){
- if ( p5 < small5pow.length ){
- v = v.mult( small5pow[p5] );
- } else {
- v = v.mult( big5pow( p5 ) );
- }
- }
- if ( p2 != 0 ){
- v.lshiftMe( p2 );
- }
- return v;
- }
+ 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'});
- //
- // another common operation
- //
- private static FDBigInt
- constructPow52( int p5, int p2 ){
- FDBigInt v = new FDBigInt( big5pow( p5 ) );
- if ( p2 != 0 ){
- v.lshiftMe( p2 );
+ /**
+ * A buffered implementation of <code>BinaryToASCIIConverter</code>.
+ */
+ 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.
+ //
+
+ // True if the dtoa() binary to decimal conversion was exact.
+ private boolean exactDecimalConversion = false;
+
+ // True if the result of the binary to decimal conversion was rounded-up
+ // at the end of the conversion process, i.e. roundUp() method was called.
+ private boolean decimalDigitsRoundedUp = false;
+
+ /**
+ * Default constructor; used for non-zero values,
+ * <code>BinaryToASCIIBuffer</code> may be thread-local and reused
+ */
+ BinaryToASCIIBuffer(){
+ this.digits = new char[20];
}
- return v;
- }
+
+ /**
+ * Creates a specialized value (positive and negative zeros).
+ */
+ BinaryToASCIIBuffer(boolean isNegative, char[] digits){
+ this.isNegative = isNegative;
+ this.decExponent = 0;
+ this.digits = digits;
+ this.firstDigitIndex = 0;
+ this.nDigits = digits.length;
+ }
- /*
- * Make a floating double into a FDBigInt.
- * This could also be structured as a FDBigInt
- * constructor, but we'd have to build a lot of knowledge
- * about floating-point representation into it, and we don't want to.
- *
- * AS A SIDE EFFECT, THIS METHOD WILL SET THE INSTANCE VARIABLES
- * bigIntExp and bigIntNBits
- *
- */
- private FDBigInt
- doubleToBigInt( double dval ){
- long lbits = Double.doubleToLongBits( dval ) & ~signMask;
- int binexp = (int)(lbits >>> expShift);
- lbits &= fractMask;
- if ( binexp > 0 ){
- lbits |= fractHOB;
- } else {
- assert lbits != 0L : lbits; // doubleToBigInt(0.0)
- binexp +=1;
- while ( (lbits & fractHOB ) == 0L){
- lbits <<= 1;
- binexp -= 1;
+ @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;
}
}
- binexp -= expBias;
- int nbits = countBits( lbits );
- /*
- * We now know where the high-order 1 bit is,
- * and we know how many there are.
- */
- int lowOrderZeros = expShift+1-nbits;
- lbits >>>= lowOrderZeros;
+
+ @Override
+ public int getDecimalExponent() {
+ return decExponent;
+ }
- bigIntExp = binexp+1-nbits;
- bigIntNBits = nbits;
- return new FDBigInt( lbits );
- }
+ @Override
+ public int getDigits(char[] digits) {
+ System.arraycopy(this.digits,firstDigitIndex,digits,0,this.nDigits);
+ return this.nDigits;
+ }
+
+ @Override
+ public boolean isNegative() {
+ return isNegative;
+ }
- /*
- * 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;
+ @Override
+ public boolean isExceptional() {
+ return false;
+ }
+
+ @Override
+ public boolean digitsRoundedUp() {
+ return decimalDigitsRoundedUp;
}
- 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) );
+
+ @Override
+ public boolean decimalDigitsExact() {
+ return exactDecimalConversion;
}
- if ( subtracting ) ulpval = - ulpval;
- return ulpval;
- }
+ private void setSign(boolean isNegative) {
+ this.isNegative = isNegative;
+ }
- /*
- * 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
- * has already been done. Exceptional cases have already been
- * stripped out.
- * In particular:
- * lvalue is a finite number (not Inf, nor NaN)
- * lvalue > 0L (not zero, nor negative).
- *
- * The only reason that we develop the digits here, rather than
- * calling on Long.toString() is that we can do it a little faster,
- * and besides want to treat trailing 0s specially. If Long.toString
- * changes, we should re-evaluate this strategy!
- */
- private void
- developLongDigits( int decExponent, long lvalue, long insignificant ){
- char digits[];
- int ndigits;
- int digitno;
- int c;
- //
- // Discard non-significant low-order bits, while rounding,
- // up to insignificant value.
- int i;
- for ( i = 0; insignificant >= 10L; i++ )
- insignificant /= 10L;
- if ( i != 0 ){
- long pow10 = long5pow[i] << i; // 10^i == 5^i * 2^i;
- long residue = lvalue % pow10;
- lvalue /= pow10;
- decExponent += i;
- if ( residue >= (pow10>>1) ){
- // round up based on the low-order bits we're discarding
- lvalue++;
+ /**
+ * This is the easy subcase --
+ * all the significant bits, after scaling, are held in lvalue.
+ * negSign and decExponent tell us what processing and scaling
+ * has already been done. Exceptional cases have already been
+ * stripped out.
+ * In particular:
+ * lvalue is a finite number (not Inf, nor NaN)
+ * lvalue > 0L (not zero, nor negative).
+ *
+ * The only reason that we develop the digits here, rather than
+ * calling on Long.toString() is that we can do it a little faster,
+ * and besides want to treat trailing 0s specially. If Long.toString
+ * changes, we should re-evaluate this strategy!
+ */
+ 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; // 10^i == 5^i * 2^i;
+ long residue = lvalue % pow10;
+ lvalue /= pow10;
+ decExponent += insignificantDigits;
+ if ( residue >= (pow10>>1) ){
+ // round up based on the low-order bits we're discarding
+ lvalue++;
+ }
}
- }
- if ( lvalue <= Integer.MAX_VALUE ){
- assert lvalue > 0L : lvalue; // lvalue <= 0
- // even easier subcase!
- // can do int arithmetic rather than long!
- int ivalue = (int)lvalue;
- ndigits = 10;
- digits = perThreadBuffer.get();
- digitno = ndigits-1;
- c = ivalue%10;
- ivalue /= 10;
- while ( c == 0 ){
- decExponent++;
+ int digitno = digits.length -1;
+ int c;
+ if ( lvalue <= Integer.MAX_VALUE ){
+ assert lvalue > 0L : lvalue; // lvalue <= 0
+ // even easier subcase!
+ // can do int arithmetic rather than long!
+ int ivalue = (int)lvalue;
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 )
- // but using long arithmetic.
- ndigits = 20;
- digits = perThreadBuffer.get();
- digitno = ndigits-1;
- c = (int)(lvalue%10L);
- lvalue /= 10L;
- while ( c == 0 ){
- decExponent++;
+ 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 )
+ // but using long arithmetic.
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');
- }
- char result [];
- ndigits -= digitno;
- result = new char[ ndigits ];
- System.arraycopy( digits, digitno, result, 0, ndigits );
- this.digits = result;
- this.decExponent = decExponent+1;
- this.nDigits = ndigits;
- }
-
- //
- // 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;
- int q = digits[ i = (nDigits-1)];
- if ( q == '9' ){
- while ( q == '9' && i > 0 ){
- digits[i] = '0';
- q = digits[--i];
- }
- if ( q == '9' ){
- // carryout! High-order 1, rest 0s, larger exp.
- decExponent += 1;
- digits[0] = '1';
- return;
+ 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');
}
- // else fall through.
- }
- digits[i] = (char)(q+1);
- decimalDigitsRoundedUp = true;
- }
-
- public boolean digitsRoundedUp() {
- return decimalDigitsRoundedUp;
- }
-
- /*
- * FIRST IMPORTANT CONSTRUCTOR: DOUBLE
- */
- public FloatingDecimal( double d )
- {
- long dBits = Double.doubleToLongBits( d );
- long fractBits;
- int binExp;
- int nSignificantBits;
-
- // discover and delete sign
- if ( (dBits&signMask) != 0 ){
- isNegative = true;
- dBits ^= signMask;
- } else {
- isNegative = false;
- }
- // Begin to unpack
- // Discover obvious special cases of NaN and Infinity.
- binExp = (int)( (dBits&expMask) >> expShift );
- fractBits = dBits&fractMask;
- if ( binExp == (int)(expMask>>expShift) ) {
- isExceptional = true;
- if ( fractBits == 0L ){
- digits = infinity;
- } else {
- digits = notANumber;
- isNegative = false; // NaN has no sign!
- }
- nDigits = digits.length;
- return;
- }
- isExceptional = false;
- // Finish unpacking
- // Normalize denormalized numbers.
- // Insert assumed high-order bit for normalized numbers.
- // Subtract exponent bias.
- if ( binExp == 0 ){
- if ( fractBits == 0L ){
- // not a denorm, just a 0!
- decExponent = 0;
- digits = zero;
- nDigits = 1;
- return;
- }
- while ( (fractBits&fractHOB) == 0L ){
- fractBits <<= 1;
- binExp -= 1;
- }
- nSignificantBits = expShift + binExp +1; // recall binExp is - shift count.
- binExp += 1;
- } else {
- fractBits |= fractHOB;
- nSignificantBits = expShift+1;
+ this.decExponent = decExponent+1;
+ this.firstDigitIndex = digitno;
+ this.nDigits = this.digits.length - digitno;
}
- binExp -= expBias;
- // call the routine that actually does all the hard work.
- dtoa( binExp, fractBits, nSignificantBits );
- }
- /*
- * SECOND IMPORTANT CONSTRUCTOR: SINGLE
- */
- public FloatingDecimal( float f )
- {
- int fBits = Float.floatToIntBits( f );
- int fractBits;
- int binExp;
- int nSignificantBits;
+ private void dtoa( int binExp, long fractBits, int nSignificantBits, boolean isCompatibleFormat)
+ {
+ assert fractBits > 0 ; // fractBits here can't be zero or negative
+ assert (fractBits & FRACT_HOB)!=0 ; // Hi-order bit should be set
+ // Examine number. Determine if it is an easy case,
+ // which we can do pretty trivially using float/long conversion,
+ // or whether we must do real work.
+ final int tailZeros = Long.numberOfTrailingZeros(fractBits);
+
+ // number of significant bits of 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
+ // values with respect to the current state.
+ decimalDigitsRoundedUp = false;
+ exactDecimalConversion = false;
- // discover and delete sign
- if ( (fBits&singleSignMask) != 0 ){
- isNegative = true;
- fBits ^= singleSignMask;
- } else {
- isNegative = false;
- }
- // Begin to unpack
- // Discover obvious special cases of NaN and Infinity.
- binExp = (fBits&singleExpMask) >> singleExpShift;
- fractBits = fBits&singleFractMask;
- if ( binExp == (singleExpMask>>singleExpShift) ) {
- isExceptional = true;
- if ( fractBits == 0L ){
- digits = infinity;
- } else {
- digits = notANumber;
- isNegative = false; // NaN has no sign!
+ // number of significant bits to the right of the point.
+ 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
+ // a long.
+ 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;
+ // }
+ //
+ }
}
- nDigits = digits.length;
- return;
- }
- isExceptional = false;
- // Finish unpacking
- // Normalize denormalized numbers.
- // Insert assumed high-order bit for normalized numbers.
- // Subtract exponent bias.
- if ( binExp == 0 ){
- if ( fractBits == 0 ){
- // not a denorm, just a 0!
- decExponent = 0;
- digits = zero;
- nDigits = 1;
- 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; // powers of 2 and powers of 5, respectively, in B
+ int S2, S5; // powers of 2 and powers of 5, respectively, in S
+ int M2, M5; // powers of 2 and powers of 5, respectively, in M
+
+ 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;
}
- while ( (fractBits&singleFractHOB) == 0 ){
- fractBits <<= 1;
- binExp -= 1;
+
+ if ( M2 < 0 ){
+ // oops.
+ // since we cannot scale M down far enough,
+ // we must scale the other values up.
+ B2 -= M2;
+ S2 -= M2;
+ M2 = 0;
}
- nSignificantBits = singleExpShift + binExp +1; // recall binExp is - shift count.
- binExp += 1;
- } else {
- fractBits |= singleFractHOB;
- nSignificantBits = singleExpShift+1;
- }
- binExp -= singleExpBias;
- // call the routine that actually does all the hard work.
- dtoa( binExp, ((long)fractBits)<<(expShift-singleExpShift), nSignificantBits );
- }
+ //
+ // 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;
- private void
- dtoa( int binExp, long fractBits, int nSignificantBits )
- {
- int nFractBits; // number of significant bits of fractBits;
- int nTinyBits; // number of these to the right of the point.
- int decExp;
+ //
+ // 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.
+ //
+ // binary digits needed to represent B, approx.
+ int Bbits = nFractBits + B2 + (( B5 < N_5_BITS.length )? N_5_BITS[B5] : ( B5*3 ));
- // Examine number. Determine if it is an easy case,
- // which we can do pretty trivially using float/long conversion,
- // or whether we must do real work.
- nFractBits = countBits( fractBits );
- nTinyBits = Math.max( 0, nFractBits - binExp - 1 );
- if ( binExp <= maxSmallBinExp && binExp >= minSmallBinExp ){
- // Look more closely at the number to decide if,
- // with scaling by 10^nTinyBits, the result will fit in
- // a long.
- if ( (nTinyBits < long5pow.length) && ((nFractBits + n5bits[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 expShift-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.
- */
- long halfULP;
- if ( nTinyBits == 0 ) {
- if ( binExp > nSignificantBits ){
- halfULP = 1L << ( binExp-nSignificantBits-1);
+ // binary digits needed to represent 10*S, approx.
+ 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){
+ // wa-hoo! They're all ints!
+ 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; // excessively large digit
+ if ( (q == 0) && ! high ){
+ // oops. Usually ignore leading zero.
+ 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; // excessively large digit
+ 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
+ // either!
+ low = true;
+ high = true;
+ }
+ digits[ndigit++] = (char)('0' + q);
+ }
+ lowDigitDifference = (b<<1) - tens;
+ exactDecimalConversion = (b == 0);
+ } else {
+ // still good! they're all longs!
+ 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; // excessively large digit
+ if ( (q == 0) && ! high ){
+ // oops. Usually ignore leading zero.
+ decExp--;
} else {
- halfULP = 0L;
+ 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; // excessively large digit
+ 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
+ // either!
+ low = true;
+ high = true;
+ }
+ digits[ndigit++] = (char)('0' + q);
}
- if ( binExp >= expShift ){
- fractBits <<= (binExp-expShift);
- } else {
- fractBits >>>= (expShift-binExp) ;
+ 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); // normalize so that division works better
+
+ 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); //Sval.mult( 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 = Bval.quoRemIteration( Sval );
+ low = (Bval.cmp( Mval ) < 0);
+ high = tenSval.addAndCmp(Bval,Mval)<=0;
+
+ assert q < 10 : q; // excessively large digit
+ if ( (q == 0) && ! high ){
+ // oops. Usually ignore leading zero.
+ 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; // excessively large digit
+ Mval = Mval.multBy10(); //Mval = Mval.mult( 10 );
+ 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; // this here only for flow analysis!
+ }
+ 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!
+ // choose based on which digits we like.
+ if ( (digits[firstDigitIndex+nDigits-1]&1) != 0 ) {
+ roundup();
+ }
+ } else if ( lowDigitDifference > 0 ){
+ roundup();
}
- developLongDigits( 0, fractBits, halfULP );
+ } 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') {
+ // carryout! High-order 1, rest 0s, larger exp.
+ decExponent += 1;
+ digits[firstDigitIndex] = '1';
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 >>>= expShift+1-nFractBits;
- * fractBits *= long5pow[ nTinyBits ];
- * halfULP = long5pow[ nTinyBits ] >> (1+nSignificantBits-nFractBits);
- * developLongDigits( -nTinyBits, fractBits, halfULP );
- * return;
- * }
- */
+ // else fall through.
}
+ digits[i] = (char) (q + 1);
+ decimalDigitsRoundedUp = true;
}
- /*
- * 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.
- */
- /*
+ /**
* Estimate decimal exponent. (If it is small-ish,
* we could double-check.)
*
@@ -630,324 +813,108 @@
* and so we can estimate
* log10(d) ~=~ log10(d2) + binExp * log10(2)
* take the floor and call it decExp.
- * FIXME -- use more precise constants here. It costs no more.
*/
- double d2 = Double.longBitsToDouble(
- expOne | ( fractBits &~ fractHOB ) );
- decExp = (int)Math.floor(
- (d2-1.5D)*0.289529654D + 0.176091259 + (double)binExp * 0.301029995663981 );
- int B2, B5; // powers of 2 and powers of 5, respectively, in B
- int S2, S5; // powers of 2 and powers of 5, respectively, in S
- int M2, M5; // powers of 2 and powers of 5, respectively, in M
- int Bbits; // binary digits needed to represent B, approx.
- int tenSbits; // binary digits needed to represent 10*S, approx.
- FDBigInt Sval, Bval, Mval;
-
- 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 (expShift+1-nFractBits) zeros. In the interest of compactness,
- * I will shift out those zeros before turning fractBits into a
- * FDBigInt. The resulting whole number will be
- * d * 2^(nFractBits-1-binExp).
- */
- fractBits >>>= (expShift+1-nFractBits);
- 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,
- // we must scale the other values up.
- 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.
- */
- char digits[] = this.digits = new char[18];
- 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 FDBigInt arithmetic.
- * We use the same algorithms, except that we "normalize"
- * our FDBigInts 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.
- */
- Bbits = nFractBits + B2 + (( B5 < n5bits.length )? n5bits[B5] : ( B5*3 ));
- tenSbits = S2+1 + (( (S5+1) < n5bits.length )? n5bits[(S5+1)] : ( (S5+1)*3 ));
- if ( Bbits < 64 && tenSbits < 64){
- if ( Bbits < 32 && tenSbits < 32){
- // wa-hoo! They're all ints!
- int b = ((int)fractBits * small5pow[B5] ) << B2;
- int s = small5pow[S5] << S2;
- int m = small5pow[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; // excessively large digit
- if ( (q == 0) && ! high ){
- // oops. Usually ignore leading zero.
- 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 ( decExp < -3 || decExp >= 8 ){
- high = low = false;
- }
- while( ! low && ! high ){
- q = b / s;
- b = 10 * ( b % s );
- m *= 10;
- assert q < 10 : q; // excessively large digit
- 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
- // either!
- low = true;
- high = true;
- }
- digits[ndigit++] = (char)('0' + q);
- }
- lowDigitDifference = (b<<1) - tens;
- exactDecimalConversion = (b == 0);
- } else {
- // still good! they're all longs!
- long b = (fractBits * long5pow[B5] ) << B2;
- long s = long5pow[S5] << S2;
- long m = long5pow[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; // excessively large digit
- if ( (q == 0) && ! high ){
- // oops. Usually ignore leading zero.
- 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 ( decExp < -3 || decExp >= 8 ){
- high = low = false;
- }
- while( ! low && ! high ){
- q = (int) ( b / s );
- b = 10 * ( b % s );
- m *= 10;
- assert q < 10 : q; // excessively large digit
- 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
- // either!
- low = true;
- high = true;
- }
- digits[ndigit++] = (char)('0' + q);
- }
- lowDigitDifference = (b<<1) - tens;
- exactDecimalConversion = (b == 0);
- }
- } else {
- FDBigInt ZeroVal = new FDBigInt(0);
- FDBigInt tenSval;
- int shiftBias;
-
- /*
- * We really must do FDBigInt arithmetic.
- * Fist, construct our FDBigInt initial values.
- */
- Bval = multPow52( new FDBigInt( fractBits ), B5, B2 );
- Sval = constructPow52( S5, S2 );
- Mval = constructPow52( M5, M2 );
-
-
- // normalize so that division works better
- Bval.lshiftMe( shiftBias = Sval.normalizeMe() );
- Mval.lshiftMe( shiftBias );
- tenSval = Sval.mult( 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 = Bval.quoRemIteration( Sval );
- Mval = Mval.mult( 10 );
- low = (Bval.cmp( Mval ) < 0);
- high = (Bval.add( Mval ).cmp( tenSval ) > 0 );
- assert q < 10 : q; // excessively large digit
- if ( (q == 0) && ! high ){
- // oops. Usually ignore leading zero.
- 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 ( decExp < -3 || decExp >= 8 ){
- high = low = false;
- }
- while( ! low && ! high ){
- q = Bval.quoRemIteration( Sval );
- Mval = Mval.mult( 10 );
- assert q < 10 : q; // excessively large digit
- low = (Bval.cmp( Mval ) < 0);
- high = (Bval.add( Mval ).cmp( tenSval ) > 0 );
- digits[ndigit++] = (char)('0' + q);
- }
- if ( high && low ){
- Bval.lshiftMe(1);
- lowDigitDifference = Bval.cmp(tenSval);
- } else {
- lowDigitDifference = 0L; // this here only for flow analysis!
- }
- exactDecimalConversion = (Bval.cmp( ZeroVal ) == 0);
- }
- this.decExponent = decExp+1;
- this.digits = digits;
- this.nDigits = ndigit;
- /*
- * Last digit gets rounded based on stopping condition.
- */
- if ( high ){
- if ( low ){
- if ( lowDigitDifference == 0L ){
- // it's a tie!
- // choose based on which digits we like.
- if ( (digits[nDigits-1]&1) != 0 ) roundup();
- } else if ( lowDigitDifference > 0 ){
- roundup();
- }
- } else {
- roundup();
+ 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); //can't be NaN here so use raw
+ int exponent = (int)((dBits & DoubleConsts.EXP_BIT_MASK) >> EXP_SHIFT) - DoubleConsts.EXP_BIAS;
+ boolean isNegative = (dBits & DoubleConsts.SIGN_BIT_MASK) != 0; // discover sign
+ if(exponent>=0 && exponent<52) { // hot path
+ 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 { //if (exponent >= 52)
+ return (int)d;
}
}
- }
+
+ private static int insignificantDigits(int insignificant) {
+ int i;
+ for ( i = 0; insignificant >= 10L; i++ ) {
+ insignificant /= 10L;
+ }
+ return i;
+ }
- public boolean decimalDigitsExact() {
- return exactDecimalConversion;
- }
+ /**
+ * Calculates
+ * <pre>
+ * insignificantDigitsForPow2(v) == insignificantDigits(1L<<v)
+ * </pre>
+ */
+ private static int insignificantDigitsForPow2(int p2) {
+ if(p2>1 && p2 < insignificantDigitsNumber.length) {
+ return insignificantDigitsNumber[p2];
+ }
+ return 0;
+ }
+
+ /**
+ * If insignificant==(1L << ixd)
+ * i = insignificantDigitsNumber[idx] is the same as:
+ * int i;
+ * for ( i = 0; insignificant >= 10L; i++ )
+ * insignificant /= 10L;
+ */
+ 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
+ };
- public String
- toString(){
- // most brain-dead version
- StringBuffer result = new StringBuffer( nDigits+8 );
- if ( isNegative ){ result.append( '-' ); }
- if ( isExceptional ){
- result.append( digits, 0, nDigits );
- } else {
- result.append( "0.");
- result.append( digits, 0, nDigits );
- result.append('e');
- result.append( decExponent );
- }
- return new String(result);
- }
+ // approximately ceil( log2( long5pow[i] ) )
+ 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,
+ };
- public String toJavaFormatString() {
- char result[] = perThreadBuffer.get();
- int i = getChars(result);
- return new String(result, 0, i);
- }
-
- private int getChars(char[] result) {
- assert nDigits <= 19 : nDigits; // generous bound on size of nDigits
- int i = 0;
- if (isNegative) { result[0] = '-'; i = 1; }
- if (isExceptional) {
- System.arraycopy(digits, 0, result, i, nDigits);
- i += nDigits;
- } else {
+ private int getChars(char[] result) {
+ assert nDigits <= 19 : nDigits; // generous bound on size of nDigits
+ int i = 0;
+ if (isNegative) {
+ result[0] = '-';
+ i = 1;
+ }
if (decExponent > 0 && decExponent < 8) {
// print digits.digits.
int charLength = Math.min(nDigits, decExponent);
- System.arraycopy(digits, 0, result, i, charLength);
+ System.arraycopy(digits, firstDigitIndex, result, i, charLength);
i += charLength;
if (charLength < decExponent) {
- charLength = decExponent-charLength;
- System.arraycopy(zero, 0, result, i, charLength);
+ charLength = decExponent - charLength;
+ Arrays.fill(result,i,i+charLength,'0');
i += charLength;
result[i++] = '.';
result[i++] = '0';
@@ -955,27 +922,27 @@
result[i++] = '.';
if (charLength < nDigits) {
int t = nDigits - charLength;
- System.arraycopy(digits, charLength, result, i, t);
+ System.arraycopy(digits, firstDigitIndex+charLength, result, i, t);
i += t;
} else {
result[i++] = '0';
}
}
- } else if (decExponent <=0 && decExponent > -3) {
+ } else if (decExponent <= 0 && decExponent > -3) {
result[i++] = '0';
result[i++] = '.';
if (decExponent != 0) {
- System.arraycopy(zero, 0, result, i, -decExponent);
+ Arrays.fill(result, i, i-decExponent, '0');
i -= decExponent;
}
- System.arraycopy(digits, 0, result, i, nDigits);
+ System.arraycopy(digits, firstDigitIndex, result, i, nDigits);
i += nDigits;
} else {
- result[i++] = digits[0];
+ result[i++] = digits[firstDigitIndex];
result[i++] = '.';
if (nDigits > 1) {
- System.arraycopy(digits, 1, result, i, nDigits-1);
- i += nDigits-1;
+ System.arraycopy(digits, firstDigitIndex+1, result, i, nDigits - 1);
+ i += nDigits - 1;
} else {
result[i++] = '0';
}
@@ -983,48 +950,776 @@
int e;
if (decExponent <= 0) {
result[i++] = '-';
- e = -decExponent+1;
+ e = -decExponent + 1;
} else {
- e = decExponent-1;
+ e = decExponent - 1;
}
// decExponent has 1, 2, or 3, digits
if (e <= 9) {
- result[i++] = (char)(e+'0');
+ result[i++] = (char) (e + '0');
} else if (e <= 99) {
- result[i++] = (char)(e/10 +'0');
- result[i++] = (char)(e%10 + '0');
+ result[i++] = (char) (e / 10 + '0');
+ result[i++] = (char) (e % 10 + '0');
} else {
- result[i++] = (char)(e/100+'0');
+ result[i++] = (char) (e / 100 + '0');
e %= 100;
- result[i++] = (char)(e/10+'0');
- result[i++] = (char)(e%10 + '0');
+ result[i++] = (char) (e / 10 + '0');
+ result[i++] = (char) (e % 10 + '0');
}
}
+ return i;
}
- 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();
+ }
+
+ /**
+ * A converter which can process an ASCII <code>String</code> representation
+ * of a single or double precision floating point value into a
+ * <code>float</code> or a <code>double</code>.
+ */
+ interface ASCIIToBinaryConverter {
+
+ double doubleValue();
+
+ float floatValue();
+
+ }
+
+ /**
+ * A <code>ASCIIToBinaryConverter</code> container for a <code>double</code>.
+ */
+ static class PreparedASCIIToBinaryBuffer implements ASCIIToBinaryConverter {
+ final private double doubleVal;
+ private int roundDir = 0;
+
+ public PreparedASCIIToBinaryBuffer(double doubleVal) {
+ this.doubleVal = doubleVal;
+ }
+
+ public PreparedASCIIToBinaryBuffer(double doubleVal, int roundDir) {
+ this.doubleVal = doubleVal;
+ this.roundDir = roundDir;
+ }
+
+ @Override
+ public double doubleValue() {
+ return doubleVal;
+ }
+
+ @Override
+ public float floatValue() {
+ return stickyRound(doubleVal,roundDir);
+ }
}
- // Per-thread buffer for string/stringbuffer conversion
- private static ThreadLocal<char[]> perThreadBuffer = new ThreadLocal<char[]>() {
- protected synchronized char[] initialValue() {
- return new char[26];
+ static final ASCIIToBinaryConverter A2BC_POSITIVE_INFINITY = new PreparedASCIIToBinaryBuffer(Double.POSITIVE_INFINITY);
+ static final ASCIIToBinaryConverter A2BC_NEGATIVE_INFINITY = new PreparedASCIIToBinaryBuffer(Double.NEGATIVE_INFINITY);
+ static final ASCIIToBinaryConverter A2BC_NOT_A_NUMBER = new PreparedASCIIToBinaryBuffer(Double.NaN);
+ static final ASCIIToBinaryConverter A2BC_POSITIVE_ZERO = new PreparedASCIIToBinaryBuffer(0.0d);
+ static final ASCIIToBinaryConverter A2BC_NEGATIVE_ZERO = new PreparedASCIIToBinaryBuffer(-0.0d);
+
+ /**
+ * A buffered implementation of <code>ASCIIToBinaryConverter</code>.
+ */
+ static class ASCIIToBinaryBuffer implements ASCIIToBinaryConverter {
+ boolean isNegative;
+ int decExponent;
+ char digits[];
+ int nDigits;
+ int roundDir = 0; // set by doubleValue
+
+ 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() {
+ return doubleValue(false);
+ }
+
+ /**
+ * Computes 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) & ~DoubleConsts.SIGN_BIT_MASK;
+ int binexp = (int) (lbits >>> EXP_SHIFT);
+ double ulpval;
+ if (subtracting && (binexp >= EXP_SHIFT) && ((lbits & DoubleConsts.SIGNIF_BIT_MASK) == 0L)) {
+ // for subtraction from normalized, powers of 2,
+ // use next-smaller exponent
+ binexp -= 1;
+ }
+ if (binexp > EXP_SHIFT) {
+ ulpval = Double.longBitsToDouble(((long) (binexp - EXP_SHIFT)) << EXP_SHIFT);
+ } else if (binexp == 0) {
+ ulpval = Double.MIN_VALUE;
+ } else {
+ ulpval = Double.longBitsToDouble(1L << (binexp - 1));
+ }
+ if (subtracting) {
+ ulpval = -ulpval;
+ }
+
+ return ulpval;
+ }
+
+ /**
+ * Takes a FloatingDecimal, which we presumably just scanned in,
+ * and finds 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.
+ */
+ private strictfp double doubleValue(boolean mustSetRoundDir) {
+ int kDigits = Math.min(nDigits, MAX_DECIMAL_DIGITS + 1);
+ long lValue;
+ double dValue;
+ double rValue;
+
+ 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, INT_DECIMAL_DIGITS);
+ 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 <= 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; // small floating integer
+ }
+ else if (exp >= 0) {
+ if (exp <= MAX_SMALL_TEN) {
+ //
+ // Can get the answer with one operation,
+ // thus one roundoff.
+ //
+ rValue = dValue * SMALL_10_POW[exp];
+ if (mustSetRoundDir) {
+ double tValue = rValue / SMALL_10_POW[exp];
+ roundDir = (tValue == dValue) ? 0
+ : (tValue < dValue) ? 1
+ : -1;
+ }
+ 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];
+ rValue = dValue * SMALL_10_POW[exp - slop];
+
+ if (mustSetRoundDir) {
+ double tValue = rValue / SMALL_10_POW[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 >= -MAX_SMALL_TEN) {
+ //
+ // Can get the answer in one division.
+ //
+ rValue = dValue / SMALL_10_POW[-exp];
+ if (mustSetRoundDir) {
+ double tValue = rValue * SMALL_10_POW[-exp];
+ 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 > 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
+ //
+ FDBigInteger bigD0 = new FDBigInteger(lValue, digits, kDigits, nDigits);
+ exp = decExponent - nDigits;
+
+ final int B5 = Math.max(0, -exp); // powers of 5 in bigB, value is not modified inside correctionLoop
+ final int D5 = Math.max(0, exp); // powers of 5 in bigD, value is not modified inside correctionLoop
+ bigD0 = bigD0.multByPow52(D5, 0);
+ bigD0.makeImmutable(); // prevent bigD0 modification inside correctionLoop
+ FDBigInteger bigD = null;
+ int prevD2 = 0;
+
+ correctionLoop:
+ while (true) {
+ // here dValue can't be NaN, Infinity or zero
+ long bigBbits = Double.doubleToRawLongBits(dValue) & ~DoubleConsts.SIGN_BIT_MASK;
+ int binexp = (int) (bigBbits >>> EXP_SHIFT);
+ bigBbits &= DoubleConsts.SIGNIF_BIT_MASK;
+ if (binexp > 0) {
+ bigBbits |= FRACT_HOB;
+ } else { // Normalize denormalized numbers.
+ assert bigBbits != 0L : bigBbits; // doubleToBigInt(0.0)
+ 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; // powers of 2 in bigB
+ int D2 = D5; // powers of 2 in bigD
+ int Ulp2; // powers of 2 in halfUlp.
+ 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 (binexp <= -DoubleConsts.EXP_BIAS) {
+ // This is going to be a denormalized number
+ // (if not actually zero).
+ // half an ULP is at 2^-(expBias+EXP_SHIFT+1)
+ 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
+ // 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
+ 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; // our candidate is too big.
+ diff = bigB.leftInplaceSub(bigD); // bigB is not user further - reuse
+ 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
+ // next smaller range.
+ Ulp2 -= 1;
+ if (Ulp2 < 0) {
+ // rats. Cannot de-scale ulp this far.
+ // must scale diff in other direction.
+ Ulp2 = 0;
+ diff = diff.leftShift(1);
+ }
+ }
+ } else if (cmpResult < 0) {
+ overvalue = false; // our candidate is too small.
+ diff = bigD.rightInplaceSub(bigB); // bigB is not user further - reuse
+ } else {
+ // the candidate is exactly right!
+ // this happens with surprising frequency
+ break correctionLoop;
+ }
+ cmpResult = diff.cmpPow52(B5, Ulp2);
+ if ((cmpResult) < 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;
+ }
+
+ /**
+ * Takes a FloatingDecimal, which we presumably just scanned in,
+ * and finds 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 conversion
+ * 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 ).
+ */
+ @Override
+ public strictfp float floatValue() {
+ int kDigits = Math.min(nDigits, SINGLE_MAX_DECIMAL_DIGITS + 1);
+ int iValue;
+ float fValue;
+ //
+ // 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 <= 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; // small floating integer
+ } 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 dValue 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 weeding out obviously out-of-range
+ // results, then convert to double and go to
+ // common hard-case code.
+ //
+ 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;
+ } else 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;
+ }
+
+ //
+ // 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
+ // algorithm 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.
+ //
+ double dValue = doubleValue(true);
+ return stickyRound(dValue, roundDir);
+ }
+
+
+ /**
+ * All the positive powers of 10 that can be
+ * represented exactly in double/float.
+ */
+ 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
};
- public void appendTo(Appendable buf) {
- char result[] = perThreadBuffer.get();
- int i = getChars(result);
- if (buf instanceof StringBuilder)
- ((StringBuilder) buf).append(result, 0, i);
- else if (buf instanceof StringBuffer)
- ((StringBuffer) buf).append(result, 0, i);
- else
- assert false;
+ 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;
+
+ }
+
+ /**
+ * Returns a <code>BinaryToASCIIConverter</code> for a <code>double</code>.
+ * The returned object is a <code>ThreadLocal</code> variable of this class.
+ *
+ * @param d The double precision value to convert.
+ * @return The converter.
+ */
+ public static BinaryToASCIIConverter getBinaryToASCIIConverter(double d) {
+ return getBinaryToASCIIConverter(d, true);
+ }
+
+ /**
+ * Returns a <code>BinaryToASCIIConverter</code> for a <code>double</code>.
+ * The returned object is a <code>ThreadLocal</code> variable of this class.
+ *
+ * @param d The double precision value to convert.
+ * @param isCompatibleFormat
+ * @return The converter.
+ */
+ static BinaryToASCIIConverter getBinaryToASCIIConverter(double d, boolean isCompatibleFormat) {
+ long dBits = Double.doubleToRawLongBits(d);
+ boolean isNegative = (dBits&DoubleConsts.SIGN_BIT_MASK) != 0; // discover sign
+ long fractBits = dBits & DoubleConsts.SIGNIF_BIT_MASK;
+ int binExp = (int)( (dBits&DoubleConsts.EXP_BIT_MASK) >> EXP_SHIFT );
+ // Discover obvious special cases of NaN and Infinity.
+ 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.
+ // Subtract exponent bias.
+ int nSignificantBits;
+ if ( binExp == 0 ){
+ if ( fractBits == 0L ){
+ // not a denorm, just a 0!
+ 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; // recall binExp is - shift count.
+ } else {
+ fractBits |= FRACT_HOB;
+ nSignificantBits = EXP_SHIFT+1;
+ }
+ binExp -= DoubleConsts.EXP_BIAS;
+ BinaryToASCIIBuffer buf = getBinaryToASCIIBuffer();
+ buf.setSign(isNegative);
+ // call the routine that actually does all the hard work.
+ 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;
+ // Discover obvious special cases of NaN and Infinity.
+ 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.
+ // Subtract exponent bias.
+ int nSignificantBits;
+ if ( binExp == 0 ){
+ if ( fractBits == 0 ){
+ // not a denorm, just a 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; // recall binExp is - shift count.
+ } else {
+ fractBits |= SINGLE_FRACT_HOB;
+ nSignificantBits = SINGLE_EXP_SHIFT+1;
+ }
+ binExp -= FloatConsts.EXP_BIAS;
+ BinaryToASCIIBuffer buf = getBinaryToASCIIBuffer();
+ buf.setSign(isNegative);
+ // call the routine that actually does all the hard work.
+ buf.dtoa(binExp, ((long)fractBits)<<(EXP_SHIFT-SINGLE_EXP_SHIFT), nSignificantBits, true);
+ return buf;
}
@SuppressWarnings("fallthrough")
- public static FloatingDecimal
- readJavaFormatString( String in ) throws NumberFormatException {
+ static ASCIIToBinaryConverter readJavaFormatString( String in ) throws NumberFormatException {
boolean isNegative = false;
boolean signSeen = false;
int decExp;
@@ -1034,10 +1729,12 @@
try{
in = in.trim(); // don't fool around with white space.
// throws NullPointerException if null
- int l = in.length();
- if ( l == 0 ) throw new NumberFormatException("empty String");
+ int len = in.length();
+ if ( len == 0 ) {
+ throw new NumberFormatException("empty String");
+ }
int i = 0;
- switch ( c = in.charAt( i ) ){
+ switch (in.charAt(i)){
case '-':
isNegative = true;
//FALLTHROUGH
@@ -1045,144 +1742,121 @@
i++;
signSeen = true;
}
-
- // Check for NaN and Infinity strings
c = in.charAt(i);
- if(c == 'N' || c == 'I') { // possible NaN or infinity
- boolean potentialNaN = false;
- char targetChars[] = null; // char array of "NaN" or "Infinity"
-
- if(c == 'N') {
- targetChars = notANumber;
- potentialNaN = true;
- } else {
- targetChars = infinity;
+ if(c == 'N') { // Check for NaN
+ if((len-i)==NAN_LENGTH && in.indexOf(NAN_REP,i)==i) {
+ return A2BC_NOT_A_NUMBER;
}
-
- // compare Input string to "NaN" or "Infinity"
- int j = 0;
- while(i < l && j < targetChars.length) {
- if(in.charAt(i) == targetChars[j]) {
- i++; j++;
+ // something went wrong, throw exception
+ break parseNumber;
+ } else if(c == 'I') { // Check for Infinity strings
+ if((len-i)==INFINITY_LENGTH && in.indexOf(INFINITY_REP,i)==i) {
+ return isNegative? A2BC_NEGATIVE_INFINITY : A2BC_POSITIVE_INFINITY;
+ }
+ // something went wrong, throw exception
+ break parseNumber;
+ } else if (c == '0') { // check for hexadecimal floating-point number
+ if (len > i+1 ) {
+ char ch = in.charAt(i+1);
+ if (ch == 'x' || ch == 'X' ) { // possible hex string
+ return parseHexString(in);
}
- else // something is amiss, throw exception
- break parseNumber;
- }
-
- // For the candidate string to be a NaN or infinity,
- // all characters in input string and target char[]
- // must be matched ==> j must equal targetChars.length
- // and i must equal l
- if( (j == targetChars.length) && (i == l) ) { // return NaN or infinity
- return (potentialNaN ? new FloatingDecimal(Double.NaN) // NaN has no sign
- : new FloatingDecimal(isNegative?
- Double.NEGATIVE_INFINITY:
- Double.POSITIVE_INFINITY)) ;
- }
- else { // something went wrong, throw exception
- break parseNumber;
- }
-
- } else if (c == '0') { // check for hexadecimal floating-point number
- if (l > i+1 ) {
- char ch = in.charAt(i+1);
- if (ch == 'x' || ch == 'X' ) // possible hex string
- return parseHexString(in);
}
} // look for and process decimal floating-point string
- char[] digits = new char[ l ];
+ char[] digits = new char[ len ];
int nDigits= 0;
boolean decSeen = false;
int decPt = 0;
int nLeadZero = 0;
int nTrailZero= 0;
- digitLoop:
- while ( i < l ){
- switch ( c = in.charAt( i ) ){
- case '0':
- if ( nDigits > 0 ){
- nTrailZero += 1;
- } else {
- nLeadZero += 1;
- }
- break; // out of switch.
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- while ( nTrailZero > 0 ){
- digits[nDigits++] = '0';
- nTrailZero -= 1;
- }
- digits[nDigits++] = c;
- break; // out of switch.
- case '.':
- if ( decSeen ){
+
+ skipLeadingZerosLoop:
+ while (i < len) {
+ c = in.charAt(i);
+ if (c == '0') {
+ nLeadZero++;
+ } else if (c == '.') {
+ if (decSeen) {
// already saw one ., this is the 2nd.
throw new NumberFormatException("multiple points");
}
decPt = i;
- if ( signSeen ){
+ if (signSeen) {
decPt -= 1;
}
decSeen = true;
- break; // out of switch.
- default:
+ } 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) {
+ // already saw one ., this is the 2nd.
+ throw new NumberFormatException("multiple points");
+ }
+ decPt = i;
+ if (signSeen) {
+ decPt -= 1;
+ }
+ decSeen = true;
+ } else {
break digitLoop;
}
i++;
}
- /*
- * 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!
- */
- if ( nDigits == 0 ){
- digits = zero;
- nDigits = 1;
- if ( nLeadZero == 0 ){
- // we saw NO DIGITS AT ALL,
- // not even a crummy 0!
- // this is not allowed.
- break parseNumber; // go throw exception
- }
-
+ 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; // go throw exception
}
-
- /* 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.
- */
+ //
+ // 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;
+ decExp = nDigits + nTrailZero;
}
- /*
- * Look for 'e' or 'E' and an optionally signed integer.
- */
- if ( (i < l) && (((c = in.charAt(i) )=='e') || (c == 'E') ) ){
+ //
+ // 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;
@@ -1196,31 +1870,21 @@
}
int expAt = i;
expLoop:
- while ( i < l ){
+ while ( i < len ){
if ( expVal >= reallyBig ){
// the next character will cause integer
// overflow.
expOverflow = true;
}
- switch ( c = in.charAt(i++) ){
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
+ c = in.charAt(i++);
+ if(c>='0' && c<='9') {
expVal = expVal*10 + ( (int)c - (int)'0' );
- continue;
- default:
+ } else {
i--; // back up.
break expLoop; // stop parsing exponent.
}
}
- int expLimit = bigDecimalExponent+nDigits+nTrailZero;
+ int expLimit = BIG_DECIMAL_EXPONENT+nDigits+nTrailZero;
if ( expOverflow || ( expVal > expLimit ) ){
//
// The intent here is to end up with
@@ -1247,1182 +1911,588 @@
// but then some trailing garbage, that might be ok.
// so we just fall through in that case.
// HUMBUG
- if ( i == expAt )
+ if ( i == expAt ) {
break parseNumber; // certainly bad
+ }
}
- /*
- * We parsed everything we could.
- * If there are leftovers, then this is not good input!
- */
- if ( i < l &&
- ((i != l - 1) ||
+ //
+ // 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; // go throw exception
}
-
- return new FloatingDecimal( isNegative, decExp, digits, nDigits, false );
+ 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 + "\"");
}
- /*
- * Take a FloatingDecimal, 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.
+ /**
+ * Rounds 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.
*/
-
- 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;
- }
+ static float stickyRound( double dval, int roundDirection ){
+ if(roundDirection!=0) {
+ long lbits = Double.doubleToRawLongBits( dval );
+ long binexp = lbits & DoubleConsts.EXP_BIT_MASK;
+ if ( binexp == 0L || binexp == DoubleConsts.EXP_BIT_MASK ){
+ // what we have here is special.
+ // don't worry, the right thing will happen.
+ return (float) dval;
}
-
- /*
- * 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 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; // 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+1) ){
- // 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 frequency
- 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 FloatingDecimal, 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 conversion
- * 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
- * algorithm 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 );
+ lbits += (long)roundDirection; // hack-o-matic.
+ return (float)Double.longBitsToDouble( lbits );
+ } else {
+ return (float)dval;
}
}
- /*
- * 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,
- 5*5,
- 5*5*5,
- 5*5*5*5,
- 5*5*5*5*5,
- 5*5*5*5*5*5,
- 5*5*5*5*5*5*5,
- 5*5*5*5*5*5*5*5,
- 5*5*5*5*5*5*5*5*5,
- 5*5*5*5*5*5*5*5*5*5,
- 5*5*5*5*5*5*5*5*5*5*5,
- 5*5*5*5*5*5*5*5*5*5*5*5,
- 5*5*5*5*5*5*5*5*5*5*5*5*5
- };
-
-
- private static final long long5pow[] = {
- 1L,
- 5L,
- 5L*5,
- 5L*5*5,
- 5L*5*5*5,
- 5L*5*5*5*5,
- 5L*5*5*5*5*5,
- 5L*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- };
-
- // approximately ceil( log2( long5pow[i] ) )
- private static final int n5bits[] = {
- 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 static final char infinity[] = { 'I', 'n', 'f', 'i', 'n', 'i', 't', 'y' };
- private static final char notANumber[] = { 'N', 'a', 'N' };
- private static final char zero[] = { '0', '0', '0', '0', '0', '0', '0', '0' };
-
-
- /*
- * Grammar is compatible with hexadecimal floating-point constants
- * described in section 6.4.4.2 of the C99 specification.
- */
- private static Pattern hexFloatPattern = null;
- private static synchronized Pattern getHexFloatPattern() {
- if (hexFloatPattern == null) {
- hexFloatPattern = Pattern.compile(
+ private static class HexFloatPattern {
+ /**
+ * Grammar is compatible with hexadecimal floating-point constants
+ * described in section 6.4.4.2 of the C99 specification.
+ */
+ private static final Pattern VALUE = Pattern.compile(
//1 234 56 7 8 9
"([-+])?0[xX](((\\p{XDigit}+)\\.?)|((\\p{XDigit}*)\\.(\\p{XDigit}+)))[pP]([-+])?(\\p{Digit}+)[fFdD]?"
);
- }
- return hexFloatPattern;
}
- /*
- * Convert string s to a suitable floating decimal; uses the
- * double constructor and set the roundDir variable appropriately
+ /**
+ * Converts string s to a suitable floating decimal; uses the
+ * double constructor and sets the roundDir variable appropriately
* in case the value is later converted to a float.
+ *
+ * @param s The <code>String</code> to parse.
*/
- static FloatingDecimal parseHexString(String s) {
- // Verify string is a member of the hexadecimal floating-point
- // string language.
- Matcher m = getHexFloatPattern().matcher(s);
- boolean validInput = m.matches();
-
- if (!validInput) {
- // Input does not match pattern
- 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.
- */
-
- // Extract significand sign
- String group1 = m.group(1);
- double sign = (( group1 == null ) || group1.equals("+"))? 1.0 : -1.0;
-
-
- // 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; // number of meaningful digits to
- // left of "decimal" point
- // (leading zeros stripped)
- int rightDigits = 0; // number of digits to right of
- // "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
- // Leading zeros never matter on the integer portion
- significandString = stripLeadingZeros(group4);
- leftDigits = significandString.length();
- }
- else {
- // Group 6 is the optional integer; leading zeros
- // never matter on the integer portion
- String group6 = stripLeadingZeros(m.group(6));
- leftDigits = group6.length();
-
- // fraction
- String group7 = m.group(7);
- rightDigits = group7.length();
-
- // Turn "integer.fraction" into "integer"+"fraction"
- significandString =
- ((group6 == null)?"":group6) + // is the null
- // check necessary?
- group7;
- }
-
- significandString = stripLeadingZeros(significandString);
- signifLength = significandString.length();
-
- /*
- * Adjust exponent as described above
- */
- if (leftDigits >= 1) { // Cases 1 and 2
- exponentAdjust = 4*(leftDigits - 1);
- } else { // Cases 3 and 4
- exponentAdjust = -4*( rightDigits - signifLength + 1);
- }
-
- // If the significand is zero, the exponent doesn't
- // matter; return a properly signed zero.
-
- if (signifLength == 0) { // Only zeros in input
- return new FloatingDecimal(sign * 0.0);
- }
- }
-
- // 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:
+ static ASCIIToBinaryConverter parseHexString(String s) {
+ // Verify string is a member of the hexadecimal floating-point
+ // string language.
+ Matcher m = HexFloatPattern.VALUE.matcher(s);
+ boolean validInput = m.matches();
+ if (!validInput) {
+ // Input does not match pattern
+ 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.
//
- // significand
- // + -
- // exponent + +infinity -infinity
- // - +0.0 -0.0
- return new FloatingDecimal(sign * (positiveExponent ?
- Double.POSITIVE_INFINITY : 0.0));
- }
-
- long rawExponent =
- (positiveExponent ? 1L : -1L) * // exponent sign
- unsignedRawExponent; // exponent magnitude
-
- // Calculate partially adjusted exponent
- 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 bitsCopied=0;
- 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
- // surprising shift semantics!
- long leadingDigit = getHexDigit(significandString, 0);
+ // 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.
+ //
+ // Extract significand sign
+ String group1 = m.group(1);
+ boolean isNegative = ((group1 != null) && group1.equals("-"));
- /*
- * 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) { // [2, 3]
- significand |= leadingDigit << 51;
- nextShift = 52 - 5;
- exponent += 1;
- }
- else if (leadingDigit <= 7) { // [4, 7]
- significand |= leadingDigit << 50;
- nextShift = 52 - 6;
- exponent += 2;
- }
- else if (leadingDigit <= 15) { // [8, f]
- 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
- // hex digits.
- 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 ) { // at least one hex input digit exists
- long currentDigit = getHexDigit(significandString, i);
-
- // from nextShift, figure out how many bits need
- // to be copied, if any
- switch(nextShift) { // must be negative
- case -1:
- // three bits need to be copied in; can
- // set round bit
- significand |= ((currentDigit & 0xEL) >> 1);
- round = (currentDigit & 0x1L) != 0L;
- break;
-
- case -2:
- // two bits need to be copied in; can
- // set round and start sticky
- significand |= ((currentDigit & 0xCL) >> 2);
- round = (currentDigit &0x2L) != 0L;
- sticky = (currentDigit & 0x1L) != 0;
- break;
-
- case -3:
- // one bit needs to be copied in
- significand |= ((currentDigit & 0x8L)>>3);
- // Now set round and start sticky, if possible
- round = (currentDigit &0x4L) != 0L;
- sticky = (currentDigit & 0x3L) != 0;
- break;
+ // 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.
+ //
- case -4:
- // all bits copied into significand; set
- // round and start sticky
- round = ((currentDigit & 0x8L) != 0); // is top bit set?
- // nonzeros in three low order bits?
- 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
- // the remaining unprocessed input.
- 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.
-
-
- // Check for overflow and update exponent accordingly.
-
- if (exponent > DoubleConsts.MAX_EXPONENT) { // Infinite result
- // overflow to properly signed infinity
- return new FloatingDecimal(sign * Double.POSITIVE_INFINITY);
- } else { // Finite return value
- if (exponent <= DoubleConsts.MAX_EXPONENT && // (Usually) normal result
- exponent >= DoubleConsts.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.
+ String significandString = null;
+ int signifLength = 0;
+ int exponentAdjust = 0;
+ {
+ int leftDigits = 0; // number of meaningful digits to
+ // left of "decimal" point
+ // (leading zeros stripped)
+ int rightDigits = 0; // number of digits to right of
+ // "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
+ // Leading zeros never matter on the integer portion
+ significandString = stripLeadingZeros(group4);
+ leftDigits = significandString.length();
+ } else {
+ // Group 6 is the optional integer; leading zeros
+ // never matter on the integer portion
+ String group6 = stripLeadingZeros(m.group(6));
+ leftDigits = group6.length();
- significand = (( (exponent +
- (long)DoubleConsts.EXP_BIAS) <<
- (DoubleConsts.SIGNIFICAND_WIDTH-1))
- & DoubleConsts.EXP_BIT_MASK) |
- (DoubleConsts.SIGNIF_BIT_MASK & significand);
-
- } else { // Subnormal or zero
- // (exponent < DoubleConsts.MIN_EXPONENT)
+ // fraction
+ String group7 = m.group(7);
+ rightDigits = group7.length();
- if (exponent < (DoubleConsts.MIN_SUB_EXPONENT -1 )) {
- // No way to round back to nonzero value
- // regardless of significand if the exponent is
- // less than -1075.
- return new FloatingDecimal(sign * 0.0);
- } else { // -1075 <= exponent <= MIN_EXPONENT -1 = -1023
- /*
- * Find bit position to round to; recompute
- * round and sticky bits, and shift
- * significand right appropriately.
- */
+ // Turn "integer.fraction" into "integer"+"fraction"
+ significandString =
+ ((group6 == null) ? "" : group6) + // is the null
+ // check necessary?
+ group7;
+ }
- sticky = sticky || round;
- round = false;
+ significandString = stripLeadingZeros(significandString);
+ signifLength = significandString.length();
- // 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;
+ //
+ // Adjust exponent as described above
+ //
+ if (leftDigits >= 1) { // Cases 1 and 2
+ exponentAdjust = 4 * (leftDigits - 1);
+ } else { // Cases 3 and 4
+ exponentAdjust = -4 * (rightDigits - signifLength + 1);
+ }
- // What to do here:
- // First, isolate the new round bit
- round = (significand & (1L << (bitsDiscarded -1))) != 0L;
- if (bitsDiscarded > 1) {
- // create mask to update sticky bits; low
- // order bitsDiscarded bits should be 1
- long mask = ~((~0L) << (bitsDiscarded -1));
- sticky = sticky || ((significand & mask) != 0L ) ;
- }
+ // If the significand is zero, the exponent doesn't
+ // matter; return a properly signed zero.
- // Now, discard the bits
- significand = significand >> bitsDiscarded;
-
- significand = (( ((long)(DoubleConsts.MIN_EXPONENT -1) + // subnorm exp.
- (long)DoubleConsts.EXP_BIAS) <<
- (DoubleConsts.SIGNIFICAND_WIDTH-1))
- & DoubleConsts.EXP_BIT_MASK) |
- (DoubleConsts.SIGNIF_BIT_MASK & significand);
+ if (signifLength == 0) { // Only zeros in input
+ return isNegative ? A2BC_NEGATIVE_ZERO : A2BC_POSITIVE_ZERO;
}
}
- // The significand variable now contains the currently
- // appropriate exponent bits too.
+ // 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
+ // - +0.0 -0.0
+ return isNegative ?
+ (positiveExponent ? A2BC_NEGATIVE_INFINITY : A2BC_NEGATIVE_ZERO)
+ : (positiveExponent ? A2BC_POSITIVE_INFINITY : A2BC_POSITIVE_ZERO);
+
+ }
+
+ long rawExponent =
+ (positiveExponent ? 1L : -1L) * // exponent sign
+ unsignedRawExponent; // exponent magnitude
+
+ // Calculate partially adjusted exponent
+ 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...
- /*
- * 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 incremented = false;
- boolean leastZero = ((significand & 1L) == 0L);
- if( ( leastZero && round && sticky ) ||
- ((!leastZero) && round )) {
- incremented = true;
- significand++;
+ // IMPORTANT: make leadingDigit a long to avoid
+ // surprising shift semantics!
+ 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) { // [2, 3]
+ significand |= leadingDigit << 51;
+ nextShift = 52 - 5;
+ exponent += 1;
+ } else if (leadingDigit <= 7) { // [4, 7]
+ significand |= leadingDigit << 50;
+ nextShift = 52 - 6;
+ exponent += 2;
+ } else if (leadingDigit <= 15) { // [8, f]
+ 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
+ // hex digits.
+ int i = 0;
+ for (i = 1;
+ i < signifLength && nextShift >= 0;
+ i++) {
+ long currentDigit = getHexDigit(significandString, i);
+ significand |= (currentDigit << nextShift);
+ nextShift -= 4;
}
- FloatingDecimal fd = new FloatingDecimal(Math.copySign(
- Double.longBitsToDouble(significand),
- sign));
+ // 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) { // at least one hex input digit exists
+ long currentDigit = getHexDigit(significandString, i);
+
+ // from nextShift, figure out how many bits need
+ // to be copied, if any
+ switch (nextShift) { // must be negative
+ case -1:
+ // three bits need to be copied in; can
+ // set round bit
+ significand |= ((currentDigit & 0xEL) >> 1);
+ round = (currentDigit & 0x1L) != 0L;
+ break;
+
+ case -2:
+ // two bits need to be copied in; can
+ // set round and start sticky
+ significand |= ((currentDigit & 0xCL) >> 2);
+ round = (currentDigit & 0x2L) != 0L;
+ sticky = (currentDigit & 0x1L) != 0;
+ break;
+
+ case -3:
+ // one bit needs to be copied in
+ significand |= ((currentDigit & 0x8L) >> 3);
+ // Now set round and start sticky, if possible
+ 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); // is top bit set?
+ // nonzeros in three low order bits?
+ sticky = (currentDigit & 0x7L) != 0;
+ break;
+
+ default:
+ throw new AssertionError("Unexpected shift distance remainder.");
+ // break;
+ }
+
+ // Round is set; sticky might be set.
- /*
- * Set roundingDir variable field of fd properly so
- * that the input string can be properly rounded to a
- * float value. There are two cases to consider:
- *
- * 1. rounding to double discards sticky bit
- * information that would change the result of a float
- * rounding (near halfway case between two floats)
- *
- * 2. rounding to double rounds up when rounding up
- * would not occur when rounding to float.
- *
- * For former case only needs to be considered when
- * the bits rounded away when casting to float are all
- * zero; otherwise, float round bit is properly set
- * and sticky will already be true.
- *
- * The lower exponent bound for the code below is the
- * minimum (normalized) subnormal exponent - 1 since a
- * value with that exponent can round up to the
- * minimum subnormal value and the sticky bit
- * information must be preserved (i.e. case 1).
- */
- if ((exponent >= FloatConsts.MIN_SUB_EXPONENT-1) &&
- (exponent <= FloatConsts.MAX_EXPONENT ) ){
- // Outside above exponent range, the float value
- // will be zero or infinity.
+ // For the sticky bit, it suffices to check the
+ // current digit and test for any nonzero digits in
+ // the remaining unprocessed input.
+ 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.
+
+ // Check for overflow and update exponent accordingly.
+ if (exponent > DoubleConsts.MAX_EXPONENT) { // Infinite result
+ // overflow to properly signed infinity
+ return isNegative ? A2BC_NEGATIVE_INFINITY : A2BC_POSITIVE_INFINITY;
+ } else { // Finite return value
+ if (exponent <= DoubleConsts.MAX_EXPONENT && // (Usually) normal result
+ exponent >= DoubleConsts.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 < DoubleConsts.MIN_EXPONENT)
+
+ if (exponent < (DoubleConsts.MIN_SUB_EXPONENT - 1)) {
+ // No way to round back to nonzero value
+ // regardless of significand if the exponent is
+ // less than -1075.
+ 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;
- /*
- * If the low-order 28 bits of a rounded double
- * significand are 0, the double could be a
- * half-way case for a rounding to float. If the
- * double value is a half-way case, the double
- * significand may have to be modified to round
- * the the right float value (see the stickyRound
- * method). If the rounding to double has lost
- * what would be float sticky bit information, the
- * double significand must be incremented. If the
- * double value's significand was itself
- * incremented, the float value may end up too
- * large so the increment should be undone.
- */
- if ((significand & 0xfffffffL) == 0x0L) {
- // For negative values, the sign of the
- // roundDir is the same as for positive values
- // since adding 1 increasing the significand's
- // magnitude and subtracting 1 decreases the
- // significand's magnitude. If neither round
- // nor sticky is true, the double value is
- // exact and no adjustment is required for a
- // proper float rounding.
- if( round || sticky) {
- if (leastZero) { // prerounding lsb is 0
- // If round and sticky were both true,
- // and the least significant
- // significand bit were 0, the rounded
- // significand would not have its
- // low-order bits be zero. Therefore,
- // we only need to adjust the
- // significand if round XOR sticky is
- // true.
- if (round ^ sticky) {
- fd.roundDir = 1;
+ // What to do here:
+ // First, isolate the new round bit
+ round = (significand & (1L << (bitsDiscarded - 1))) != 0L;
+ if (bitsDiscarded > 1) {
+ // create mask to update sticky bits; low
+ // order bitsDiscarded bits should be 1
+ long mask = ~((~0L) << (bitsDiscarded - 1));
+ sticky = sticky || ((significand & mask) != 0L);
+ }
+
+ // Now, discard the bits
+ significand = significand >> bitsDiscarded;
+
+ significand = ((((long) (DoubleConsts.MIN_EXPONENT - 1) + // subnorm exp.
+ (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 );
+
+ int roundDir = 0;
+ //
+ // Set roundingDir variable field of fd properly so
+ // that the input string can be properly rounded to a
+ // float value. There are two cases to consider:
+ //
+ // 1. rounding to double discards sticky bit
+ // information that would change the result of a float
+ // rounding (near halfway case between two floats)
+ //
+ // 2. rounding to double rounds up when rounding up
+ // would not occur when rounding to float.
+ //
+ // For former case only needs to be considered when
+ // the bits rounded away when casting to float are all
+ // zero; otherwise, float round bit is properly set
+ // and sticky will already be true.
+ //
+ // The lower exponent bound for the code below is the
+ // minimum (normalized) subnormal exponent - 1 since a
+ // value with that exponent can round up to the
+ // minimum subnormal value and the sticky bit
+ // information must be preserved (i.e. case 1).
+ //
+ if ((exponent >= FloatConsts.MIN_SUB_EXPONENT - 1) &&
+ (exponent <= FloatConsts.MAX_EXPONENT)) {
+ // Outside above exponent range, the float value
+ // will be zero or infinity.
+
+ //
+ // If the low-order 28 bits of a rounded double
+ // significand are 0, the double could be a
+ // half-way case for a rounding to float. If the
+ // double value is a half-way case, the double
+ // significand may have to be modified to round
+ // the the right float value (see the stickyRound
+ // method). If the rounding to double has lost
+ // what would be float sticky bit information, the
+ // double significand must be incremented. If the
+ // double value's significand was itself
+ // incremented, the float value may end up too
+ // large so the increment should be undone.
+ //
+ if ((significand & 0xfffffffL) == 0x0L) {
+ // For negative values, the sign of the
+ // roundDir is the same as for positive values
+ // since adding 1 increasing the significand's
+ // magnitude and subtracting 1 decreases the
+ // significand's magnitude. If neither round
+ // nor sticky is true, the double value is
+ // exact and no adjustment is required for a
+ // proper float rounding.
+ if (round || sticky) {
+ if (leastZero) { // prerounding lsb is 0
+ // If round and sticky were both true,
+ // and the least significant
+ // significand bit were 0, the rounded
+ // significand would not have its
+ // low-order bits be zero. Therefore,
+ // we only need to adjust the
+ // significand if round XOR sticky is
+ // true.
+ if (round ^ sticky) {
+ roundDir = 1;
+ }
+ } else { // prerounding lsb is 1
+ // If the prerounding lsb is 1 and the
+ // resulting significand has its
+ // low-order bits zero, the significand
+ // was incremented. Here, we undo the
+ // increment, which will ensure the
+ // right guard and sticky bits for the
+ // float rounding.
+ if (round) {
+ roundDir = -1;
+ }
}
}
- else { // prerounding lsb is 1
- // If the prerounding lsb is 1 and the
- // resulting significand has its
- // low-order bits zero, the significand
- // was incremented. Here, we undo the
- // increment, which will ensure the
- // right guard and sticky bits for the
- // float rounding.
- if (round)
- fd.roundDir = -1;
- }
}
}
+ return new PreparedASCIIToBinaryBuffer(value,roundDir);
}
-
- fd.fromHex = true;
- return fd;
}
- }
}
/**
- * Return <code>s</code> with any leading zeros removed.
+ * Returns <code>s</code> with any leading zeros removed.
*/
static String stripLeadingZeros(String s) {
- return s.replaceFirst("^0+", "");
+// return s.replaceFirst("^0+", "");
+ 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;
}
/**
- * Extract a hexadecimal digit from position <code>position</code>
+ * Extracts a hexadecimal digit from position <code>position</code>
* of string <code>s</code>.
*/
static int getHexDigit(String s, int position) {
@@ -2433,6 +2503,4 @@
}
return value;
}
-
-
}
--- a/jdk/src/share/classes/sun/misc/FormattedFloatingDecimal.java Thu Jun 06 11:39:34 2013 -0700
+++ b/jdk/src/share/classes/sun/misc/FormattedFloatingDecimal.java Wed Jun 05 21:01:02 2013 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,422 +25,118 @@
package sun.misc;
-import sun.misc.DoubleConsts;
-import sun.misc.FloatConsts;
-import java.util.regex.*;
+import java.util.Arrays;
public class FormattedFloatingDecimal{
- boolean isExceptional;
- boolean isNegative;
- int decExponent; // value set at construction, then immutable
- int decExponentRounded;
- char digits[];
- 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 };
- private Form form;
+
+ public static FormattedFloatingDecimal valueOf(double d, int precision, Form form){
+ FloatingDecimal.BinaryToASCIIConverter fdConverter =
+ FloatingDecimal.getBinaryToASCIIConverter(d, form == Form.COMPATIBLE);
+ return new FormattedFloatingDecimal(precision,form, fdConverter);
+ }
+
+ private int decExponentRounded;
+ private char[] mantissa;
+ private char[] exponent;
- private FormattedFloatingDecimal( boolean negSign, int decExponent, char []digits, int n, boolean e, int precision, Form form )
- {
- isNegative = negSign;
- isExceptional = e;
- this.decExponent = decExponent;
- this.digits = digits;
- this.nDigits = n;
- this.precision = precision;
- this.form = form;
+ private static final ThreadLocal<Object> threadLocalCharBuffer =
+ new ThreadLocal<Object>() {
+ @Override
+ protected Object initialValue() {
+ return new char[20];
+ }
+ };
+
+ private static char[] getBuffer(){
+ return (char[]) threadLocalCharBuffer.get();
}
- /*
- * Constants of the implementation
- * Most are IEEE-754 related.
- * (There are more really boring constants at the end.)
- */
- static final long signMask = 0x8000000000000000L;
- static final long expMask = 0x7ff0000000000000L;
- static final long fractMask= ~(signMask|expMask);
- static final int expShift = 52;
- static final int expBias = 1023;
- static final long fractHOB = ( 1L<<expShift ); // assumed High-Order bit
- 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;
- static final long lowbytes = ~highbyte;
-
- static final int singleSignMask = 0x80000000;
- static final int singleExpMask = 0x7f800000;
- static final int singleFractMask = ~(singleSignMask|singleExpMask);
- 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,
- * inclusive.
- */
- private static int
- countBits( long v ){
- //
- // the strategy is to shift until we get a non-zero sign bit
- // then shift until we have no bits left, counting the difference.
- // we do byte shifting as a hack. Hope it helps.
- //
- if ( v == 0L ) return 0;
-
- while ( ( v & highbyte ) == 0L ){
- v <<= 8;
- }
- while ( v > 0L ) { // i.e. while ((v&highbit) == 0L )
- v <<= 1;
+ private FormattedFloatingDecimal(int precision, Form form, FloatingDecimal.BinaryToASCIIConverter fdConverter) {
+ if (fdConverter.isExceptional()) {
+ this.mantissa = fdConverter.toJavaFormatString().toCharArray();
+ this.exponent = null;
+ return;
}
-
- int n = 0;
- while (( v & lowbytes ) != 0L ){
- v <<= 8;
- n += 8;
- }
- while ( v != 0L ){
- v <<= 1;
- n += 1;
- }
- return n;
- }
-
- /*
- * Keep big powers of 5 handy for future reference.
- */
- private static FDBigInt b5p[];
-
- private static synchronized FDBigInt
- big5pow( int p ){
- assert p >= 0 : p; // negative power of 5
- if ( b5p == null ){
- b5p = new FDBigInt[ p+1 ];
- }else if (b5p.length <= p ){
- FDBigInt t[] = new FDBigInt[ p+1 ];
- System.arraycopy( b5p, 0, t, 0, b5p.length );
- b5p = t;
- }
- if ( b5p[p] != null )
- return b5p[p];
- else if ( p < small5pow.length )
- return b5p[p] = new FDBigInt( small5pow[p] );
- else if ( p < long5pow.length )
- return b5p[p] = new FDBigInt( long5pow[p] );
- else {
- // construct the value.
- // recursively.
- int q, r;
- // in order to compute 5^p,
- // compute its square root, 5^(p/2) and square.
- // or, let q = p / 2, r = p -q, then
- // 5^p = 5^(q+r) = 5^q * 5^r
- q = p >> 1;
- r = p - q;
- FDBigInt bigq = b5p[q];
- if ( bigq == null )
- bigq = big5pow ( q );
- if ( r < small5pow.length ){
- return (b5p[p] = bigq.mult( small5pow[r] ) );
- }else{
- FDBigInt bigr = b5p[ r ];
- if ( bigr == null )
- bigr = big5pow( r );
- return (b5p[p] = bigq.mult( bigr ) );
- }
+ char[] digits = getBuffer();
+ int nDigits = fdConverter.getDigits(digits);
+ int decExp = fdConverter.getDecimalExponent();
+ int exp;
+ boolean isNegative = fdConverter.isNegative();
+ switch (form) {
+ case COMPATIBLE:
+ exp = decExp;
+ this.decExponentRounded = exp;
+ fillCompatible(precision, digits, nDigits, exp, isNegative);
+ break;
+ case DECIMAL_FLOAT:
+ exp = applyPrecision(decExp, digits, nDigits, decExp + precision);
+ fillDecimal(precision, digits, nDigits, exp, isNegative);
+ this.decExponentRounded = exp;
+ break;
+ case SCIENTIFIC:
+ exp = applyPrecision(decExp, digits, nDigits, precision + 1);
+ fillScientific(precision, digits, nDigits, exp, isNegative);
+ this.decExponentRounded = exp;
+ break;
+ case GENERAL:
+ exp = applyPrecision(decExp, digits, nDigits, precision);
+ // adjust precision to be the number of digits to right of decimal
+ // the real exponent to be output is actually exp - 1, not exp
+ if (exp - 1 < -4 || exp - 1 >= precision) {
+ // form = Form.SCIENTIFIC;
+ precision--;
+ fillScientific(precision, digits, nDigits, exp, isNegative);
+ } else {
+ // form = Form.DECIMAL_FLOAT;
+ precision = precision - exp;
+ fillDecimal(precision, digits, nDigits, exp, isNegative);
+ }
+ this.decExponentRounded = exp;
+ break;
+ default:
+ assert false;
}
}
- //
- // a common operation
- //
- private static FDBigInt
- multPow52( FDBigInt v, int p5, int p2 ){
- if ( p5 != 0 ){
- if ( p5 < small5pow.length ){
- v = v.mult( small5pow[p5] );
- } else {
- v = v.mult( big5pow( p5 ) );
- }
- }
- if ( p2 != 0 ){
- v.lshiftMe( p2 );
- }
- return v;
- }
-
- //
- // another common operation
- //
- private static FDBigInt
- constructPow52( int p5, int p2 ){
- FDBigInt v = new FDBigInt( big5pow( p5 ) );
- if ( p2 != 0 ){
- v.lshiftMe( p2 );
- }
- return v;
+ // returns the exponent after rounding has been done by applyPrecision
+ public int getExponentRounded() {
+ return decExponentRounded - 1;
}
- /*
- * Make a floating double into a FDBigInt.
- * This could also be structured as a FDBigInt
- * constructor, but we'd have to build a lot of knowledge
- * about floating-point representation into it, and we don't want to.
- *
- * AS A SIDE EFFECT, THIS METHOD WILL SET THE INSTANCE VARIABLES
- * bigIntExp and bigIntNBits
- *
- */
- private FDBigInt
- doubleToBigInt( double dval ){
- long lbits = Double.doubleToLongBits( dval ) & ~signMask;
- int binexp = (int)(lbits >>> expShift);
- lbits &= fractMask;
- if ( binexp > 0 ){
- lbits |= fractHOB;
- } else {
- assert lbits != 0L : lbits; // doubleToBigInt(0.0)
- binexp +=1;
- while ( (lbits & fractHOB ) == 0L){
- lbits <<= 1;
- binexp -= 1;
- }
- }
- binexp -= expBias;
- int nbits = countBits( lbits );
- /*
- * We now know where the high-order 1 bit is,
- * and we know how many there are.
- */
- int lowOrderZeros = expShift+1-nbits;
- lbits >>>= lowOrderZeros;
-
- bigIntExp = binexp+1-nbits;
- bigIntNBits = nbits;
- return new FDBigInt( lbits );
- }
-
- /*
- * 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 );
+ public char[] getMantissa(){
+ return mantissa;
}
-
- /*
- * This is the easy subcase --
- * all the significant bits, after scaling, are held in lvalue.
- * negSign and decExponent tell us what processing and scaling
- * has already been done. Exceptional cases have already been
- * stripped out.
- * In particular:
- * lvalue is a finite number (not Inf, nor NaN)
- * lvalue > 0L (not zero, nor negative).
- *
- * The only reason that we develop the digits here, rather than
- * calling on Long.toString() is that we can do it a little faster,
- * and besides want to treat trailing 0s specially. If Long.toString
- * changes, we should re-evaluate this strategy!
- */
- private void
- developLongDigits( int decExponent, long lvalue, long insignificant ){
- char digits[];
- int ndigits;
- int digitno;
- int c;
- //
- // Discard non-significant low-order bits, while rounding,
- // up to insignificant value.
- int i;
- for ( i = 0; insignificant >= 10L; i++ )
- insignificant /= 10L;
- if ( i != 0 ){
- long pow10 = long5pow[i] << i; // 10^i == 5^i * 2^i;
- long residue = lvalue % pow10;
- lvalue /= pow10;
- decExponent += i;
- if ( residue >= (pow10>>1) ){
- // round up based on the low-order bits we're discarding
- lvalue++;
- }
- }
- if ( lvalue <= Integer.MAX_VALUE ){
- assert lvalue > 0L : lvalue; // lvalue <= 0
- // even easier subcase!
- // can do int arithmetic rather than long!
- int ivalue = (int)lvalue;
- ndigits = 10;
- digits = perThreadBuffer.get();
- digitno = ndigits-1;
- 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 )
- // but using long arithmetic.
- ndigits = 20;
- digits = perThreadBuffer.get();
- digitno = ndigits-1;
- 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');
- }
- char result [];
- ndigits -= digitno;
- result = new char[ ndigits ];
- System.arraycopy( digits, digitno, result, 0, ndigits );
- this.digits = result;
- this.decExponent = decExponent+1;
- this.nDigits = ndigits;
+ public char[] getExponent(){
+ return exponent;
}
- //
- // 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;
- int q = digits[ i = (nDigits-1)];
- if ( q == '9' ){
- while ( q == '9' && i > 0 ){
- digits[i] = '0';
- q = digits[--i];
- }
- if ( q == '9' ){
- // carryout! High-order 1, rest 0s, larger exp.
- decExponent += 1;
- digits[0] = '1';
- return;
- }
- // else fall through.
+ /**
+ * Returns new decExp in case of overflow.
+ */
+ private static int applyPrecision(int decExp, char[] digits, int nDigits, int prec) {
+ if (prec >= nDigits || prec < 0) {
+ // no rounding necessary
+ return decExp;
}
- digits[i] = (char)(q+1);
- }
-
- // Given the desired number of digits predict the result's exponent.
- private int checkExponent(int length) {
- if (length >= nDigits || length < 0)
- return decExponent;
-
- for (int i = 0; i < length; i++)
- if (digits[i] != '9')
- // a '9' anywhere in digits will absorb the round
- return decExponent;
- return decExponent + (digits[length] >= '5' ? 1 : 0);
- }
-
- // Unlike roundup(), this method does not modify digits. It also
- // rounds at a particular precision.
- private char [] applyPrecision(int length) {
- char [] result = new char[nDigits];
- for (int i = 0; i < result.length; i++) result[i] = '0';
-
- if (length >= nDigits || length < 0) {
- // no rounding necessary
- System.arraycopy(digits, 0, result, 0, nDigits);
- return result;
- }
- if (length == 0) {
+ if (prec == 0) {
// only one digit (0 or 1) is returned because the precision
// excludes all significant digits
if (digits[0] >= '5') {
- result[0] = '1';
+ digits[0] = '1';
+ Arrays.fill(digits, 1, nDigits, '0');
+ return decExp + 1;
+ } else {
+ Arrays.fill(digits, 0, nDigits, '0');
+ return decExp;
}
- return result;
}
-
- int i = length;
- int q = digits[i];
- if (q >= '5' && i > 0) {
+ int q = digits[prec];
+ if (q >= '5') {
+ int i = prec;
q = digits[--i];
if ( q == '9' ) {
while ( q == '9' && i > 0 ){
@@ -448,1319 +144,206 @@
}
if ( q == '9' ){
// carryout! High-order 1, rest 0s, larger exp.
- result[0] = '1';
- return result;
+ digits[0] = '1';
+ Arrays.fill(digits, 1, nDigits, '0');
+ return decExp+1;
}
}
- result[i] = (char)(q + 1);
- }
- while (--i >= 0) {
- result[i] = digits[i];
- }
- return result;
- }
-
- /*
- * FIRST IMPORTANT CONSTRUCTOR: DOUBLE
- */
- public FormattedFloatingDecimal( double d )
- {
- this(d, Integer.MAX_VALUE, Form.COMPATIBLE);
- }
-
- public FormattedFloatingDecimal( double d, int precision, Form form )
- {
- long dBits = Double.doubleToLongBits( d );
- long fractBits;
- int binExp;
- int nSignificantBits;
-
- this.precision = precision;
- this.form = form;
-
- // discover and delete sign
- if ( (dBits&signMask) != 0 ){
- isNegative = true;
- dBits ^= signMask;
+ digits[i] = (char)(q + 1);
+ Arrays.fill(digits, i+1, nDigits, '0');
} else {
- isNegative = false;
- }
- // Begin to unpack
- // Discover obvious special cases of NaN and Infinity.
- binExp = (int)( (dBits&expMask) >> expShift );
- fractBits = dBits&fractMask;
- if ( binExp == (int)(expMask>>expShift) ) {
- isExceptional = true;
- if ( fractBits == 0L ){
- digits = infinity;
- } else {
- digits = notANumber;
- isNegative = false; // NaN has no sign!
- }
- nDigits = digits.length;
- return;
- }
- isExceptional = false;
- // Finish unpacking
- // Normalize denormalized numbers.
- // Insert assumed high-order bit for normalized numbers.
- // Subtract exponent bias.
- if ( binExp == 0 ){
- if ( fractBits == 0L ){
- // not a denorm, just a 0!
- decExponent = 0;
- digits = zero;
- nDigits = 1;
- return;
- }
- while ( (fractBits&fractHOB) == 0L ){
- fractBits <<= 1;
- binExp -= 1;
- }
- nSignificantBits = expShift + binExp +1; // recall binExp is - shift count.
- binExp += 1;
- } else {
- fractBits |= fractHOB;
- nSignificantBits = expShift+1;
+ Arrays.fill(digits, prec, nDigits, '0');
}
- binExp -= expBias;
- // call the routine that actually does all the hard work.
- dtoa( binExp, fractBits, nSignificantBits );
- }
-
- /*
- * SECOND IMPORTANT CONSTRUCTOR: SINGLE
- */
- public FormattedFloatingDecimal( float f )
- {
- this(f, Integer.MAX_VALUE, Form.COMPATIBLE);
- }
- public FormattedFloatingDecimal( float f, int precision, Form form )
- {
- int fBits = Float.floatToIntBits( f );
- int fractBits;
- int binExp;
- int nSignificantBits;
-
- this.precision = precision;
- this.form = form;
-
- // discover and delete sign
- if ( (fBits&singleSignMask) != 0 ){
- isNegative = true;
- fBits ^= singleSignMask;
- } else {
- isNegative = false;
- }
- // Begin to unpack
- // Discover obvious special cases of NaN and Infinity.
- binExp = (fBits&singleExpMask) >> singleExpShift;
- fractBits = fBits&singleFractMask;
- if ( binExp == (singleExpMask>>singleExpShift) ) {
- isExceptional = true;
- if ( fractBits == 0L ){
- digits = infinity;
- } else {
- digits = notANumber;
- isNegative = false; // NaN has no sign!
- }
- nDigits = digits.length;
- return;
- }
- isExceptional = false;
- // Finish unpacking
- // Normalize denormalized numbers.
- // Insert assumed high-order bit for normalized numbers.
- // Subtract exponent bias.
- if ( binExp == 0 ){
- if ( fractBits == 0 ){
- // not a denorm, just a 0!
- decExponent = 0;
- digits = zero;
- nDigits = 1;
- return;
- }
- while ( (fractBits&singleFractHOB) == 0 ){
- fractBits <<= 1;
- binExp -= 1;
- }
- nSignificantBits = singleExpShift + binExp +1; // recall binExp is - shift count.
- binExp += 1;
- } else {
- fractBits |= singleFractHOB;
- nSignificantBits = singleExpShift+1;
- }
- binExp -= singleExpBias;
- // call the routine that actually does all the hard work.
- dtoa( binExp, ((long)fractBits)<<(expShift-singleExpShift), nSignificantBits );
+ return decExp;
}
- private void
- dtoa( int binExp, long fractBits, int nSignificantBits )
- {
- int nFractBits; // number of significant bits of fractBits;
- int nTinyBits; // number of these to the right of the point.
- int decExp;
-
- // Examine number. Determine if it is an easy case,
- // which we can do pretty trivially using float/long conversion,
- // or whether we must do real work.
- nFractBits = countBits( fractBits );
- nTinyBits = Math.max( 0, nFractBits - binExp - 1 );
- if ( binExp <= maxSmallBinExp && binExp >= minSmallBinExp ){
- // Look more closely at the number to decide if,
- // with scaling by 10^nTinyBits, the result will fit in
- // a long.
- if ( (nTinyBits < long5pow.length) && ((nFractBits + n5bits[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 expShift-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.
- */
- long halfULP;
- if ( nTinyBits == 0 ) {
- if ( binExp > nSignificantBits ){
- halfULP = 1L << ( binExp-nSignificantBits-1);
- } else {
- halfULP = 0L;
- }
- if ( binExp >= expShift ){
- fractBits <<= (binExp-expShift);
- } else {
- fractBits >>>= (expShift-binExp) ;
- }
- developLongDigits( 0, fractBits, halfULP );
- 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 >>>= expShift+1-nFractBits;
- * fractBits *= long5pow[ nTinyBits ];
- * halfULP = long5pow[ nTinyBits ] >> (1+nSignificantBits-nFractBits);
- * developLongDigits( -nTinyBits, fractBits, halfULP );
- * return;
- * }
- */
+ /**
+ * Fills mantissa and exponent char arrays for compatible format.
+ */
+ private void fillCompatible(int precision, char[] digits, int nDigits, int exp, boolean isNegative) {
+ int startIndex = isNegative ? 1 : 0;
+ if (exp > 0 && exp < 8) {
+ // print digits.digits.
+ if (nDigits < exp) {
+ int extraZeros = exp - nDigits;
+ mantissa = create(isNegative, nDigits + extraZeros + 2);
+ System.arraycopy(digits, 0, mantissa, startIndex, nDigits);
+ Arrays.fill(mantissa, startIndex + nDigits, startIndex + nDigits + extraZeros, '0');
+ mantissa[startIndex + nDigits + extraZeros] = '.';
+ mantissa[startIndex + nDigits + extraZeros+1] = '0';
+ } else if (exp < nDigits) {
+ int t = Math.min(nDigits - exp, precision);
+ mantissa = create(isNegative, exp + 1 + t);
+ System.arraycopy(digits, 0, mantissa, startIndex, exp);
+ mantissa[startIndex + exp ] = '.';
+ System.arraycopy(digits, exp, mantissa, startIndex+exp+1, t);
+ } else { // exp == digits.length
+ mantissa = create(isNegative, nDigits + 2);
+ System.arraycopy(digits, 0, mantissa, startIndex, nDigits);
+ mantissa[startIndex + nDigits ] = '.';
+ mantissa[startIndex + nDigits +1] = '0';
}
- }
- /*
- * 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.
- */
-
- /*
- * Estimate decimal exponent. (If it is small-ish,
- * we could double-check.)
- *
- * First, scale the mantissa bits such that 1 <= d2 < 2.
- * We are then going to estimate
- * log10(d2) ~=~ (d2-1.5)/1.5 + log(1.5)
- * and so we can estimate
- * log10(d) ~=~ log10(d2) + binExp * log10(2)
- * take the floor and call it decExp.
- * FIXME -- use more precise constants here. It costs no more.
- */
- double d2 = Double.longBitsToDouble(
- expOne | ( fractBits &~ fractHOB ) );
- decExp = (int)Math.floor(
- (d2-1.5D)*0.289529654D + 0.176091259 + (double)binExp * 0.301029995663981 );
- int B2, B5; // powers of 2 and powers of 5, respectively, in B
- int S2, S5; // powers of 2 and powers of 5, respectively, in S
- int M2, M5; // powers of 2 and powers of 5, respectively, in M
- int Bbits; // binary digits needed to represent B, approx.
- int tenSbits; // binary digits needed to represent 10*S, approx.
- FDBigInt Sval, Bval, Mval;
-
- 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 (expShift+1-nFractBits) zeros. In the interest of compactness,
- * I will shift out those zeros before turning fractBits into a
- * FDBigInt. The resulting whole number will be
- * d * 2^(nFractBits-1-binExp).
- */
- fractBits >>>= (expShift+1-nFractBits);
- 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,
- // we must scale the other values up.
- B2 -= M2;
- S2 -= M2;
- M2 = 0;
- }
- /*
- * Construct, Scale, iterate.
- * Some day, we'll write a stopping test that takes
- * account of the assymetry 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.
- */
- char digits[] = this.digits = new char[18];
- 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 FDBigInt arithmetic.
- * We use the same algorithms, except that we "normalize"
- * our FDBigInts 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 assymetry 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.
- */
- Bbits = nFractBits + B2 + (( B5 < n5bits.length )? n5bits[B5] : ( B5*3 ));
- tenSbits = S2+1 + (( (S5+1) < n5bits.length )? n5bits[(S5+1)] : ( (S5+1)*3 ));
- if ( Bbits < 64 && tenSbits < 64){
- if ( Bbits < 32 && tenSbits < 32){
- // wa-hoo! They're all ints!
- int b = ((int)fractBits * small5pow[B5] ) << B2;
- int s = small5pow[S5] << S2;
- int m = small5pow[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; // excessively large digit
- if ( (q == 0) && ! high ){
- // oops. Usually ignore leading zero.
- decExp--;
- } else {
- digits[ndigit++] = (char)('0' + q);
+ } else if (exp <= 0 && exp > -3) {
+ int zeros = Math.max(0, Math.min(-exp, precision));
+ int t = Math.max(0, Math.min(nDigits, precision + exp));
+ // write '0' s before the significant digits
+ if (zeros > 0) {
+ mantissa = create(isNegative, zeros + 2 + t);
+ mantissa[startIndex] = '0';
+ mantissa[startIndex+1] = '.';
+ Arrays.fill(mantissa, startIndex + 2, startIndex + 2 + zeros, '0');
+ if (t > 0) {
+ // copy only when significant digits are within the precision
+ System.arraycopy(digits, 0, mantissa, startIndex + 2 + zeros, t);
}
- /*
- * 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 (! (form == Form.COMPATIBLE && -3 < decExp && decExp < 8)) {
- high = low = false;
- }
- while( ! low && ! high ){
- q = b / s;
- b = 10 * ( b % s );
- m *= 10;
- assert q < 10 : q; // excessively large digit
- 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
- // either!
- low = true;
- high = true;
- }
- digits[ndigit++] = (char)('0' + q);
- }
- lowDigitDifference = (b<<1) - tens;
+ } else if (t > 0) {
+ mantissa = create(isNegative, zeros + 2 + t);
+ mantissa[startIndex] = '0';
+ mantissa[startIndex + 1] = '.';
+ // copy only when significant digits are within the precision
+ System.arraycopy(digits, 0, mantissa, startIndex + 2, t);
} else {
- // still good! they're all longs!
- long b = (fractBits * long5pow[B5] ) << B2;
- long s = long5pow[S5] << S2;
- long m = long5pow[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; // excessively large digit
- if ( (q == 0) && ! high ){
- // oops. Usually ignore leading zero.
- 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 (! (form == Form.COMPATIBLE && -3 < decExp && decExp < 8)) {
- high = low = false;
- }
- while( ! low && ! high ){
- q = (int) ( b / s );
- b = 10 * ( b % s );
- m *= 10;
- assert q < 10 : q; // excessively large digit
- 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
- // either!
- low = true;
- high = true;
- }
- digits[ndigit++] = (char)('0' + q);
- }
- lowDigitDifference = (b<<1) - tens;
+ this.mantissa = create(isNegative, 1);
+ this.mantissa[startIndex] = '0';
}
} else {
- FDBigInt tenSval;
- int shiftBias;
-
- /*
- * We really must do FDBigInt arithmetic.
- * Fist, construct our FDBigInt initial values.
- */
- Bval = multPow52( new FDBigInt( fractBits ), B5, B2 );
- Sval = constructPow52( S5, S2 );
- Mval = constructPow52( M5, M2 );
-
-
- // normalize so that division works better
- Bval.lshiftMe( shiftBias = Sval.normalizeMe() );
- Mval.lshiftMe( shiftBias );
- tenSval = Sval.mult( 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 = Bval.quoRemIteration( Sval );
- Mval = Mval.mult( 10 );
- low = (Bval.cmp( Mval ) < 0);
- high = (Bval.add( Mval ).cmp( tenSval ) > 0 );
- assert q < 10 : q; // excessively large digit
- if ( (q == 0) && ! high ){
- // oops. Usually ignore leading zero.
- decExp--;
+ if (nDigits > 1) {
+ mantissa = create(isNegative, nDigits + 1);
+ mantissa[startIndex] = digits[0];
+ mantissa[startIndex + 1] = '.';
+ System.arraycopy(digits, 1, mantissa, startIndex + 2, nDigits - 1);
} else {
- digits[ndigit++] = (char)('0' + q);
+ mantissa = create(isNegative, 3);
+ mantissa[startIndex] = digits[0];
+ mantissa[startIndex + 1] = '.';
+ mantissa[startIndex + 2] = '0';
}
- /*
- * 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 (! (form == Form.COMPATIBLE && -3 < decExp && decExp < 8)) {
- high = low = false;
- }
- while( ! low && ! high ){
- q = Bval.quoRemIteration( Sval );
- Mval = Mval.mult( 10 );
- assert q < 10 : q; // excessively large digit
- low = (Bval.cmp( Mval ) < 0);
- high = (Bval.add( Mval ).cmp( tenSval ) > 0 );
- digits[ndigit++] = (char)('0' + q);
+ int e, expStartIntex;
+ boolean isNegExp = (exp <= 0);
+ if (isNegExp) {
+ e = -exp + 1;
+ expStartIntex = 1;
+ } else {
+ e = exp - 1;
+ expStartIntex = 0;
}
- if ( high && low ){
- Bval.lshiftMe(1);
- lowDigitDifference = Bval.cmp(tenSval);
- } else
- lowDigitDifference = 0L; // this here only for flow analysis!
- }
- this.decExponent = decExp+1;
- this.digits = digits;
- this.nDigits = ndigit;
- /*
- * Last digit gets rounded based on stopping condition.
- */
- if ( high ){
- if ( low ){
- if ( lowDigitDifference == 0L ){
- // it's a tie!
- // choose based on which digits we like.
- if ( (digits[nDigits-1]&1) != 0 ) roundup();
- } else if ( lowDigitDifference > 0 ){
- roundup();
- }
+ // decExponent has 1, 2, or 3, digits
+ if (e <= 9) {
+ exponent = create(isNegExp,1);
+ exponent[expStartIntex] = (char) (e + '0');
+ } else if (e <= 99) {
+ exponent = create(isNegExp,2);
+ exponent[expStartIntex] = (char) (e / 10 + '0');
+ exponent[expStartIntex+1] = (char) (e % 10 + '0');
} else {
- roundup();
+ exponent = create(isNegExp,3);
+ exponent[expStartIntex] = (char) (e / 100 + '0');
+ e %= 100;
+ exponent[expStartIntex+1] = (char) (e / 10 + '0');
+ exponent[expStartIntex+2] = (char) (e % 10 + '0');
}
}
}
- public String
- toString(){
- // most brain-dead version
- StringBuffer result = new StringBuffer( nDigits+8 );
- if ( isNegative ){ result.append( '-' ); }
- if ( isExceptional ){
- result.append( digits, 0, nDigits );
- } else {
- result.append( "0.");
- result.append( digits, 0, nDigits );
- result.append('e');
- result.append( decExponent );
- }
- return new String(result);
- }
-
- // returns the exponent before rounding
- public int getExponent() {
- return decExponent - 1;
- }
-
- // returns the exponent after rounding has been done by applyPrecision
- public int getExponentRounded() {
- return decExponentRounded - 1;
- }
-
- public int getChars(char[] result) {
- assert nDigits <= 19 : nDigits; // generous bound on size of nDigits
- int i = 0;
- if (isNegative) { result[0] = '-'; i = 1; }
- if (isExceptional) {
- System.arraycopy(digits, 0, result, i, nDigits);
- i += nDigits;
+ private static char[] create(boolean isNegative, int size) {
+ if(isNegative) {
+ char[] r = new char[size +1];
+ r[0] = '-';
+ return r;
} else {
- char digits [] = this.digits;
- int exp = decExponent;
- switch (form) {
- case COMPATIBLE:
- break;
- case DECIMAL_FLOAT:
- exp = checkExponent(decExponent + precision);
- digits = applyPrecision(decExponent + precision);
- break;
- case SCIENTIFIC:
- exp = checkExponent(precision + 1);
- digits = applyPrecision(precision + 1);
- break;
- case GENERAL:
- exp = checkExponent(precision);
- digits = applyPrecision(precision);
- // adjust precision to be the number of digits to right of decimal
- // the real exponent to be output is actually exp - 1, not exp
- if (exp - 1 < -4 || exp - 1 >= precision) {
- form = Form.SCIENTIFIC;
- precision--;
- } else {
- form = Form.DECIMAL_FLOAT;
- precision = precision - exp;
- }
- break;
- default:
- assert false;
- }
- decExponentRounded = exp;
-
- if (exp > 0
- && ((form == Form.COMPATIBLE && (exp < 8))
- || (form == Form.DECIMAL_FLOAT)))
- {
- // print digits.digits.
- int charLength = Math.min(nDigits, exp);
- System.arraycopy(digits, 0, result, i, charLength);
- i += charLength;
- if (charLength < exp) {
- charLength = exp-charLength;
- for (int nz = 0; nz < charLength; nz++)
- result[i++] = '0';
- // Do not append ".0" for formatted floats since the user
- // may request that it be omitted. It is added as necessary
- // by the Formatter.
- if (form == Form.COMPATIBLE) {
- result[i++] = '.';
- result[i++] = '0';
- }
- } else {
- // Do not append ".0" for formatted floats since the user
- // may request that it be omitted. It is added as necessary
- // by the Formatter.
- if (form == Form.COMPATIBLE) {
- result[i++] = '.';
- if (charLength < nDigits) {
- int t = Math.min(nDigits - charLength, precision);
- System.arraycopy(digits, charLength, result, i, t);
- i += t;
- } else {
- result[i++] = '0';
- }
- } else {
- int t = Math.min(nDigits - charLength, precision);
- if (t > 0) {
- result[i++] = '.';
- System.arraycopy(digits, charLength, result, i, t);
- i += t;
- }
- }
- }
- } else if (exp <= 0
- && ((form == Form.COMPATIBLE && exp > -3)
- || (form == Form.DECIMAL_FLOAT)))
- {
- // print 0.0* digits
- result[i++] = '0';
- if (exp != 0) {
- // write '0' s before the significant digits
- int t = Math.min(-exp, precision);
- if (t > 0) {
- result[i++] = '.';
- for (int nz = 0; nz < t; nz++)
- result[i++] = '0';
- }
- }
- int t = Math.min(digits.length, precision + exp);
- if (t > 0) {
- if (i == 1)
- result[i++] = '.';
- // copy only when significant digits are within the precision
- System.arraycopy(digits, 0, result, i, t);
- i += t;
- }
- } else {
- result[i++] = digits[0];
- if (form == Form.COMPATIBLE) {
- result[i++] = '.';
- if (nDigits > 1) {
- System.arraycopy(digits, 1, result, i, nDigits-1);
- i += nDigits-1;
- } else {
- result[i++] = '0';
- }
- result[i++] = 'E';
- } else {
- if (nDigits > 1) {
- int t = Math.min(nDigits -1, precision);
- if (t > 0) {
- result[i++] = '.';
- System.arraycopy(digits, 1, result, i, t);
- i += t;
- }
- }
- result[i++] = 'e';
- }
- int e;
- if (exp <= 0) {
- result[i++] = '-';
- e = -exp+1;
- } else {
- if (form != Form.COMPATIBLE)
- result[i++] = '+';
- e = exp-1;
- }
- // decExponent has 1, 2, or 3, digits
- if (e <= 9) {
- if (form != Form.COMPATIBLE)
- result[i++] = '0';
- 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;
- }
-
- // Per-thread buffer for string/stringbuffer conversion
- private static ThreadLocal<char[]> perThreadBuffer = new ThreadLocal<char[]>() {
- protected synchronized char[] initialValue() {
- return new char[26];
- }
- };
-
- /*
- * 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;
+ return new char[size];
}
}
/*
- * 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 ).
+ * Fills mantissa char arrays for DECIMAL_FLOAT format.
+ * Exponent should be equal to null.
*/
-
- 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';
+ private void fillDecimal(int precision, char[] digits, int nDigits, int exp, boolean isNegative) {
+ int startIndex = isNegative ? 1 : 0;
+ if (exp > 0) {
+ // print digits.digits.
+ if (nDigits < exp) {
+ mantissa = create(isNegative,exp);
+ System.arraycopy(digits, 0, mantissa, startIndex, nDigits);
+ Arrays.fill(mantissa, startIndex + nDigits, startIndex + exp, '0');
+ // Do not append ".0" for formatted floats since the user
+ // may request that it be omitted. It is added as necessary
+ // by the Formatter.
+ } else {
+ int t = Math.min(nDigits - exp, precision);
+ mantissa = create(isNegative, exp + (t > 0 ? (t + 1) : 0));
+ System.arraycopy(digits, 0, mantissa, startIndex, exp);
+ // Do not append ".0" for formatted floats since the user
+ // may request that it be omitted. It is added as necessary
+ // by the Formatter.
+ if (t > 0) {
+ mantissa[startIndex + exp] = '.';
+ System.arraycopy(digits, exp, mantissa, startIndex + exp + 1, t);
+ }
}
- 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 (exp <= 0) {
+ int zeros = Math.max(0, Math.min(-exp, precision));
+ int t = Math.max(0, Math.min(nDigits, precision + exp));
+ // write '0' s before the significant digits
+ if (zeros > 0) {
+ mantissa = create(isNegative, zeros + 2 + t);
+ mantissa[startIndex] = '0';
+ mantissa[startIndex+1] = '.';
+ Arrays.fill(mantissa, startIndex + 2, startIndex + 2 + zeros, '0');
+ if (t > 0) {
+ // copy only when significant digits are within the precision
+ System.arraycopy(digits, 0, mantissa, startIndex + 2 + zeros, t);
}
- } 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;
-
+ } else if (t > 0) {
+ mantissa = create(isNegative, zeros + 2 + t);
+ mantissa[startIndex] = '0';
+ mantissa[startIndex + 1] = '.';
+ // copy only when significant digits are within the precision
+ System.arraycopy(digits, 0, mantissa, startIndex + 2, t);
+ } else {
+ this.mantissa = create(isNegative, 1);
+ this.mantissa[startIndex] = '0';
}
- /*
- * 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.
+ /**
+ * Fills mantissa and exponent char arrays for SCIENTIFIC format.
*/
- 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,
- 5*5,
- 5*5*5,
- 5*5*5*5,
- 5*5*5*5*5,
- 5*5*5*5*5*5,
- 5*5*5*5*5*5*5,
- 5*5*5*5*5*5*5*5,
- 5*5*5*5*5*5*5*5*5,
- 5*5*5*5*5*5*5*5*5*5,
- 5*5*5*5*5*5*5*5*5*5*5,
- 5*5*5*5*5*5*5*5*5*5*5*5,
- 5*5*5*5*5*5*5*5*5*5*5*5*5
- };
-
-
- private static final long long5pow[] = {
- 1L,
- 5L,
- 5L*5,
- 5L*5*5,
- 5L*5*5*5,
- 5L*5*5*5*5,
- 5L*5*5*5*5*5,
- 5L*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- };
-
- // approximately ceil( log2( long5pow[i] ) )
- private static final int n5bits[] = {
- 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 static final char infinity[] = { 'I', 'n', 'f', 'i', 'n', 'i', 't', 'y' };
- private static final char notANumber[] = { 'N', 'a', 'N' };
- private static final char zero[] = { '0', '0', '0', '0', '0', '0', '0', '0' };
+ private void fillScientific(int precision, char[] digits, int nDigits, int exp, boolean isNegative) {
+ int startIndex = isNegative ? 1 : 0;
+ int t = Math.max(0, Math.min(nDigits - 1, precision));
+ if (t > 0) {
+ mantissa = create(isNegative, t + 2);
+ mantissa[startIndex] = digits[0];
+ mantissa[startIndex + 1] = '.';
+ System.arraycopy(digits, 1, mantissa, startIndex + 2, t);
+ } else {
+ mantissa = create(isNegative, 1);
+ mantissa[startIndex] = digits[0];
+ }
+ char expSign;
+ int e;
+ if (exp <= 0) {
+ expSign = '-';
+ e = -exp + 1;
+ } else {
+ expSign = '+' ;
+ e = exp - 1;
+ }
+ // decExponent has 1, 2, or 3, digits
+ if (e <= 9) {
+ exponent = new char[] { expSign,
+ '0', (char) (e + '0') };
+ } else if (e <= 99) {
+ exponent = new char[] { expSign,
+ (char) (e / 10 + '0'), (char) (e % 10 + '0') };
+ } else {
+ char hiExpChar = (char) (e / 100 + '0');
+ e %= 100;
+ exponent = new char[] { expSign,
+ hiExpChar, (char) (e / 10 + '0'), (char) (e % 10 + '0') };
+ }
+ }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/misc/FloatingDecimal/OldFDBigIntForTest.java Wed Jun 05 21:01:02 2013 -0700
@@ -0,0 +1,491 @@
+/*
+ * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+//package sun.misc;
+
+/*
+ * A really, really simple bigint package
+ * tailored to the needs of floating base conversion.
+ */
+class OldFDBigIntForTest {
+ int nWords; // number of words used
+ int data[]; // value: data[0] is least significant
+
+
+ public OldFDBigIntForTest( int v ){
+ nWords = 1;
+ data = new int[1];
+ data[0] = v;
+ }
+
+ public OldFDBigIntForTest( long v ){
+ data = new int[2];
+ data[0] = (int)v;
+ data[1] = (int)(v>>>32);
+ nWords = (data[1]==0) ? 1 : 2;
+ }
+
+ public OldFDBigIntForTest( OldFDBigIntForTest other ){
+ data = new int[nWords = other.nWords];
+ System.arraycopy( other.data, 0, data, 0, nWords );
+ }
+
+ private OldFDBigIntForTest( int [] d, int n ){
+ data = d;
+ nWords = n;
+ }
+
+ public OldFDBigIntForTest( long seed, char digit[], int nd0, int nd ){
+ int n= (nd+8)/9; // estimate size needed.
+ if ( n < 2 ) n = 2;
+ data = new int[n]; // allocate enough space
+ data[0] = (int)seed; // starting value
+ data[1] = (int)(seed>>>32);
+ nWords = (data[1]==0) ? 1 : 2;
+ int i = nd0;
+ int limit = nd-5; // slurp digits 5 at a time.
+ int v;
+ while ( i < limit ){
+ int ilim = i+5;
+ v = (int)digit[i++]-(int)'0';
+ while( i <ilim ){
+ v = 10*v + (int)digit[i++]-(int)'0';
+ }
+ multaddMe( 100000, v); // ... where 100000 is 10^5.
+ }
+ int factor = 1;
+ v = 0;
+ while ( i < nd ){
+ v = 10*v + (int)digit[i++]-(int)'0';
+ factor *= 10;
+ }
+ if ( factor != 1 ){
+ multaddMe( factor, v );
+ }
+ }
+
+ /*
+ * Left shift by c bits.
+ * Shifts this in place.
+ */
+ public void
+ lshiftMe( int c )throws IllegalArgumentException {
+ if ( c <= 0 ){
+ if ( c == 0 )
+ return; // silly.
+ else
+ throw new IllegalArgumentException("negative shift count");
+ }
+ int wordcount = c>>5;
+ int bitcount = c & 0x1f;
+ int anticount = 32-bitcount;
+ int t[] = data;
+ int s[] = data;
+ if ( nWords+wordcount+1 > t.length ){
+ // reallocate.
+ t = new int[ nWords+wordcount+1 ];
+ }
+ int target = nWords+wordcount;
+ int src = nWords-1;
+ if ( bitcount == 0 ){
+ // special hack, since an anticount of 32 won't go!
+ System.arraycopy( s, 0, t, wordcount, nWords );
+ target = wordcount-1;
+ } else {
+ t[target--] = s[src]>>>anticount;
+ while ( src >= 1 ){
+ t[target--] = (s[src]<<bitcount) | (s[--src]>>>anticount);
+ }
+ t[target--] = s[src]<<bitcount;
+ }
+ while( target >= 0 ){
+ t[target--] = 0;
+ }
+ data = t;
+ nWords += wordcount + 1;
+ // may have constructed high-order word of 0.
+ // if so, trim it
+ while ( nWords > 1 && data[nWords-1] == 0 )
+ nWords--;
+ }
+
+ /*
+ * normalize this number by shifting until
+ * the MSB of the number is at 0x08000000.
+ * This is in preparation for quoRemIteration, below.
+ * The idea is that, to make division easier, we want the
+ * divisor to be "normalized" -- usually this means shifting
+ * the MSB into the high words sign bit. But because we know that
+ * the quotient will be 0 < q < 10, we would like to arrange that
+ * the dividend not span up into another word of precision.
+ * (This needs to be explained more clearly!)
+ */
+ public int
+ normalizeMe() throws IllegalArgumentException {
+ int src;
+ int wordcount = 0;
+ int bitcount = 0;
+ int v = 0;
+ for ( src= nWords-1 ; src >= 0 && (v=data[src]) == 0 ; src--){
+ wordcount += 1;
+ }
+ if ( src < 0 ){
+ // oops. Value is zero. Cannot normalize it!
+ throw new IllegalArgumentException("zero value");
+ }
+ /*
+ * In most cases, we assume that wordcount is zero. This only
+ * makes sense, as we try not to maintain any high-order
+ * words full of zeros. In fact, if there are zeros, we will
+ * simply SHORTEN our number at this point. Watch closely...
+ */
+ nWords -= wordcount;
+ /*
+ * Compute how far left we have to shift v s.t. its highest-
+ * order bit is in the right place. Then call lshiftMe to
+ * do the work.
+ */
+ if ( (v & 0xf0000000) != 0 ){
+ // will have to shift up into the next word.
+ // too bad.
+ for( bitcount = 32 ; (v & 0xf0000000) != 0 ; bitcount-- )
+ v >>>= 1;
+ } else {
+ while ( v <= 0x000fffff ){
+ // hack: byte-at-a-time shifting
+ v <<= 8;
+ bitcount += 8;
+ }
+ while ( v <= 0x07ffffff ){
+ v <<= 1;
+ bitcount += 1;
+ }
+ }
+ if ( bitcount != 0 )
+ lshiftMe( bitcount );
+ return bitcount;
+ }
+
+ /*
+ * Multiply a OldFDBigIntForTest by an int.
+ * Result is a new OldFDBigIntForTest.
+ */
+ public OldFDBigIntForTest
+ mult( int iv ) {
+ long v = iv;
+ int r[];
+ long p;
+
+ // guess adequate size of r.
+ r = new int[ ( v * ((long)data[nWords-1]&0xffffffffL) > 0xfffffffL ) ? nWords+1 : nWords ];
+ p = 0L;
+ for( int i=0; i < nWords; i++ ) {
+ p += v * ((long)data[i]&0xffffffffL);
+ r[i] = (int)p;
+ p >>>= 32;
+ }
+ if ( p == 0L){
+ return new OldFDBigIntForTest( r, nWords );
+ } else {
+ r[nWords] = (int)p;
+ return new OldFDBigIntForTest( r, nWords+1 );
+ }
+ }
+
+ /*
+ * Multiply a OldFDBigIntForTest by an int and add another int.
+ * Result is computed in place.
+ * Hope it fits!
+ */
+ public void
+ multaddMe( int iv, int addend ) {
+ long v = iv;
+ long p;
+
+ // unroll 0th iteration, doing addition.
+ p = v * ((long)data[0]&0xffffffffL) + ((long)addend&0xffffffffL);
+ data[0] = (int)p;
+ p >>>= 32;
+ for( int i=1; i < nWords; i++ ) {
+ p += v * ((long)data[i]&0xffffffffL);
+ data[i] = (int)p;
+ p >>>= 32;
+ }
+ if ( p != 0L){
+ data[nWords] = (int)p; // will fail noisily if illegal!
+ nWords++;
+ }
+ }
+
+ /*
+ * Multiply a OldFDBigIntForTest by another OldFDBigIntForTest.
+ * Result is a new OldFDBigIntForTest.
+ */
+ public OldFDBigIntForTest
+ mult( OldFDBigIntForTest other ){
+ // crudely guess adequate size for r
+ int r[] = new int[ nWords + other.nWords ];
+ int i;
+ // I think I am promised zeros...
+
+ for( i = 0; i < this.nWords; i++ ){
+ long v = (long)this.data[i] & 0xffffffffL; // UNSIGNED CONVERSION
+ long p = 0L;
+ int j;
+ for( j = 0; j < other.nWords; j++ ){
+ p += ((long)r[i+j]&0xffffffffL) + v*((long)other.data[j]&0xffffffffL); // UNSIGNED CONVERSIONS ALL 'ROUND.
+ r[i+j] = (int)p;
+ p >>>= 32;
+ }
+ r[i+j] = (int)p;
+ }
+ // compute how much of r we actually needed for all that.
+ for ( i = r.length-1; i> 0; i--)
+ if ( r[i] != 0 )
+ break;
+ return new OldFDBigIntForTest( r, i+1 );
+ }
+
+ /*
+ * Add one OldFDBigIntForTest to another. Return a OldFDBigIntForTest
+ */
+ public OldFDBigIntForTest
+ add( OldFDBigIntForTest other ){
+ int i;
+ int a[], b[];
+ int n, m;
+ long c = 0L;
+ // arrange such that a.nWords >= b.nWords;
+ // n = a.nWords, m = b.nWords
+ if ( this.nWords >= other.nWords ){
+ a = this.data;
+ n = this.nWords;
+ b = other.data;
+ m = other.nWords;
+ } else {
+ a = other.data;
+ n = other.nWords;
+ b = this.data;
+ m = this.nWords;
+ }
+ int r[] = new int[ n ];
+ for ( i = 0; i < n; i++ ){
+ c += (long)a[i] & 0xffffffffL;
+ if ( i < m ){
+ c += (long)b[i] & 0xffffffffL;
+ }
+ r[i] = (int) c;
+ c >>= 32; // signed shift.
+ }
+ if ( c != 0L ){
+ // oops -- carry out -- need longer result.
+ int s[] = new int[ r.length+1 ];
+ System.arraycopy( r, 0, s, 0, r.length );
+ s[i++] = (int)c;
+ return new OldFDBigIntForTest( s, i );
+ }
+ return new OldFDBigIntForTest( r, i );
+ }
+
+ /*
+ * Subtract one OldFDBigIntForTest from another. Return a OldFDBigIntForTest
+ * Assert that the result is positive.
+ */
+ public OldFDBigIntForTest
+ sub( OldFDBigIntForTest other ){
+ int r[] = new int[ this.nWords ];
+ int i;
+ int n = this.nWords;
+ int m = other.nWords;
+ int nzeros = 0;
+ long c = 0L;
+ for ( i = 0; i < n; i++ ){
+ c += (long)this.data[i] & 0xffffffffL;
+ if ( i < m ){
+ c -= (long)other.data[i] & 0xffffffffL;
+ }
+ if ( ( r[i] = (int) c ) == 0 )
+ nzeros++;
+ else
+ nzeros = 0;
+ c >>= 32; // signed shift
+ }
+ assert c == 0L : c; // borrow out of subtract
+ assert dataInRangeIsZero(i, m, other); // negative result of subtract
+ return new OldFDBigIntForTest( r, n-nzeros );
+ }
+
+ private static boolean dataInRangeIsZero(int i, int m, OldFDBigIntForTest other) {
+ while ( i < m )
+ if (other.data[i++] != 0)
+ return false;
+ return true;
+ }
+
+ /*
+ * Compare OldFDBigIntForTest with another OldFDBigIntForTest. Return an integer
+ * >0: this > other
+ * 0: this == other
+ * <0: this < other
+ */
+ public int
+ cmp( OldFDBigIntForTest other ){
+ int i;
+ if ( this.nWords > other.nWords ){
+ // if any of my high-order words is non-zero,
+ // then the answer is evident
+ int j = other.nWords-1;
+ for ( i = this.nWords-1; i > j ; i-- )
+ if ( this.data[i] != 0 ) return 1;
+ }else if ( this.nWords < other.nWords ){
+ // if any of other's high-order words is non-zero,
+ // then the answer is evident
+ int j = this.nWords-1;
+ for ( i = other.nWords-1; i > j ; i-- )
+ if ( other.data[i] != 0 ) return -1;
+ } else{
+ i = this.nWords-1;
+ }
+ for ( ; i > 0 ; i-- )
+ if ( this.data[i] != other.data[i] )
+ break;
+ // careful! want unsigned compare!
+ // use brute force here.
+ int a = this.data[i];
+ int b = other.data[i];
+ if ( a < 0 ){
+ // a is really big, unsigned
+ if ( b < 0 ){
+ return a-b; // both big, negative
+ } else {
+ return 1; // b not big, answer is obvious;
+ }
+ } else {
+ // a is not really big
+ if ( b < 0 ) {
+ // but b is really big
+ return -1;
+ } else {
+ return a - b;
+ }
+ }
+ }
+
+ /*
+ * Compute
+ * q = (int)( this / S )
+ * this = 10 * ( this mod S )
+ * Return q.
+ * This is the iteration step of digit development for output.
+ * We assume that S has been normalized, as above, and that
+ * "this" has been lshift'ed accordingly.
+ * Also assume, of course, that the result, q, can be expressed
+ * as an integer, 0 <= q < 10.
+ */
+ public int
+ quoRemIteration( OldFDBigIntForTest S )throws IllegalArgumentException {
+ // ensure that this and S have the same number of
+ // digits. If S is properly normalized and q < 10 then
+ // this must be so.
+ if ( nWords != S.nWords ){
+ throw new IllegalArgumentException("disparate values");
+ }
+ // estimate q the obvious way. We will usually be
+ // right. If not, then we're only off by a little and
+ // will re-add.
+ int n = nWords-1;
+ long q = ((long)data[n]&0xffffffffL) / (long)S.data[n];
+ long diff = 0L;
+ for ( int i = 0; i <= n ; i++ ){
+ diff += ((long)data[i]&0xffffffffL) - q*((long)S.data[i]&0xffffffffL);
+ data[i] = (int)diff;
+ diff >>= 32; // N.B. SIGNED shift.
+ }
+ if ( diff != 0L ) {
+ // damn, damn, damn. q is too big.
+ // add S back in until this turns +. This should
+ // not be very many times!
+ long sum = 0L;
+ while ( sum == 0L ){
+ sum = 0L;
+ for ( int i = 0; i <= n; i++ ){
+ sum += ((long)data[i]&0xffffffffL) + ((long)S.data[i]&0xffffffffL);
+ data[i] = (int) sum;
+ sum >>= 32; // Signed or unsigned, answer is 0 or 1
+ }
+ /*
+ * Originally the following line read
+ * "if ( sum !=0 && sum != -1 )"
+ * but that would be wrong, because of the
+ * treatment of the two values as entirely unsigned,
+ * it would be impossible for a carry-out to be interpreted
+ * as -1 -- it would have to be a single-bit carry-out, or
+ * +1.
+ */
+ assert sum == 0 || sum == 1 : sum; // carry out of division correction
+ q -= 1;
+ }
+ }
+ // finally, we can multiply this by 10.
+ // it cannot overflow, right, as the high-order word has
+ // at least 4 high-order zeros!
+ long p = 0L;
+ for ( int i = 0; i <= n; i++ ){
+ p += 10*((long)data[i]&0xffffffffL);
+ data[i] = (int)p;
+ p >>= 32; // SIGNED shift.
+ }
+ assert p == 0L : p; // Carry out of *10
+ return (int)q;
+ }
+
+ public long
+ longValue(){
+ // if this can be represented as a long, return the value
+ assert this.nWords > 0 : this.nWords; // longValue confused
+
+ if (this.nWords == 1)
+ return ((long)data[0]&0xffffffffL);
+
+ assert dataInRangeIsZero(2, this.nWords, this); // value too big
+ assert data[1] >= 0; // value too big
+ return ((long)(data[1]) << 32) | ((long)data[0]&0xffffffffL);
+ }
+
+ public String
+ toString() {
+ StringBuffer r = new StringBuffer(30);
+ r.append('[');
+ int i = Math.min( nWords-1, data.length-1) ;
+ if ( nWords > data.length ){
+ r.append( "("+data.length+"<"+nWords+"!)" );
+ }
+ for( ; i> 0 ; i-- ){
+ r.append( Integer.toHexString( data[i] ) );
+ r.append(' ');
+ }
+ r.append( Integer.toHexString( data[0] ) );
+ r.append(']');
+ return new String( r );
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/misc/FloatingDecimal/OldFloatingDecimalForTest.java Wed Jun 05 21:01:02 2013 -0700
@@ -0,0 +1,2436 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+//package sun.misc;
+
+import sun.misc.DoubleConsts;
+import sun.misc.FloatConsts;
+import java.util.regex.*;
+
+public class OldFloatingDecimalForTest{
+ boolean isExceptional;
+ boolean isNegative;
+ int decExponent;
+ char digits[];
+ int nDigits;
+ int bigIntExp;
+ int bigIntNBits;
+ boolean mustSetRoundDir = false;
+ boolean fromHex = false;
+ int roundDir = 0; // set by doubleValue
+
+ /*
+ * The fields below provides 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.
+ */
+
+ // True if the dtoa() binary to decimal conversion was exact.
+ boolean exactDecimalConversion = false;
+
+ // True if the result of the binary to decimal conversion was rounded-up
+ // at the end of the conversion process, i.e. roundUp() method was called.
+ boolean decimalDigitsRoundedUp = false;
+
+ private OldFloatingDecimalForTest( boolean negSign, int decExponent, char []digits, int n, boolean e )
+ {
+ isNegative = negSign;
+ isExceptional = e;
+ this.decExponent = decExponent;
+ this.digits = digits;
+ this.nDigits = n;
+ }
+
+ /*
+ * Constants of the implementation
+ * Most are IEEE-754 related.
+ * (There are more really boring constants at the end.)
+ */
+ static final long signMask = 0x8000000000000000L;
+ static final long expMask = 0x7ff0000000000000L;
+ static final long fractMask= ~(signMask|expMask);
+ static final int expShift = 52;
+ static final int expBias = 1023;
+ static final long fractHOB = ( 1L<<expShift ); // assumed High-Order bit
+ 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;
+ static final long lowbytes = ~highbyte;
+
+ static final int singleSignMask = 0x80000000;
+ static final int singleExpMask = 0x7f800000;
+ static final int singleFractMask = ~(singleSignMask|singleExpMask);
+ 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,
+ * inclusive.
+ */
+ private static int
+ countBits( long v ){
+ //
+ // the strategy is to shift until we get a non-zero sign bit
+ // then shift until we have no bits left, counting the difference.
+ // we do byte shifting as a hack. Hope it helps.
+ //
+ if ( v == 0L ) return 0;
+
+ while ( ( v & highbyte ) == 0L ){
+ v <<= 8;
+ }
+ while ( v > 0L ) { // i.e. while ((v&highbit) == 0L )
+ v <<= 1;
+ }
+
+ int n = 0;
+ while (( v & lowbytes ) != 0L ){
+ v <<= 8;
+ n += 8;
+ }
+ while ( v != 0L ){
+ v <<= 1;
+ n += 1;
+ }
+ return n;
+ }
+
+ /*
+ * Keep big powers of 5 handy for future reference.
+ */
+ private static OldFDBigIntForTest b5p[];
+
+ private static synchronized OldFDBigIntForTest
+ big5pow( int p ){
+ assert p >= 0 : p; // negative power of 5
+ if ( b5p == null ){
+ b5p = new OldFDBigIntForTest[ p+1 ];
+ }else if (b5p.length <= p ){
+ OldFDBigIntForTest t[] = new OldFDBigIntForTest[ p+1 ];
+ System.arraycopy( b5p, 0, t, 0, b5p.length );
+ b5p = t;
+ }
+ if ( b5p[p] != null )
+ return b5p[p];
+ else if ( p < small5pow.length )
+ return b5p[p] = new OldFDBigIntForTest( small5pow[p] );
+ else if ( p < long5pow.length )
+ return b5p[p] = new OldFDBigIntForTest( long5pow[p] );
+ else {
+ // construct the value.
+ // recursively.
+ int q, r;
+ // in order to compute 5^p,
+ // compute its square root, 5^(p/2) and square.
+ // or, let q = p / 2, r = p -q, then
+ // 5^p = 5^(q+r) = 5^q * 5^r
+ q = p >> 1;
+ r = p - q;
+ OldFDBigIntForTest bigq = b5p[q];
+ if ( bigq == null )
+ bigq = big5pow ( q );
+ if ( r < small5pow.length ){
+ return (b5p[p] = bigq.mult( small5pow[r] ) );
+ }else{
+ OldFDBigIntForTest bigr = b5p[ r ];
+ if ( bigr == null )
+ bigr = big5pow( r );
+ return (b5p[p] = bigq.mult( bigr ) );
+ }
+ }
+ }
+
+ //
+ // a common operation
+ //
+ private static OldFDBigIntForTest
+ multPow52( OldFDBigIntForTest v, int p5, int p2 ){
+ if ( p5 != 0 ){
+ if ( p5 < small5pow.length ){
+ v = v.mult( small5pow[p5] );
+ } else {
+ v = v.mult( big5pow( p5 ) );
+ }
+ }
+ if ( p2 != 0 ){
+ v.lshiftMe( p2 );
+ }
+ return v;
+ }
+
+ //
+ // another common operation
+ //
+ private static OldFDBigIntForTest
+ constructPow52( int p5, int p2 ){
+ OldFDBigIntForTest v = new OldFDBigIntForTest( big5pow( p5 ) );
+ if ( p2 != 0 ){
+ v.lshiftMe( p2 );
+ }
+ return v;
+ }
+
+ /*
+ * Make a floating double into a OldFDBigIntForTest.
+ * This could also be structured as a OldFDBigIntForTest
+ * constructor, but we'd have to build a lot of knowledge
+ * about floating-point representation into it, and we don't want to.
+ *
+ * AS A SIDE EFFECT, THIS METHOD WILL SET THE INSTANCE VARIABLES
+ * bigIntExp and bigIntNBits
+ *
+ */
+ private OldFDBigIntForTest
+ doubleToBigInt( double dval ){
+ long lbits = Double.doubleToLongBits( dval ) & ~signMask;
+ int binexp = (int)(lbits >>> expShift);
+ lbits &= fractMask;
+ if ( binexp > 0 ){
+ lbits |= fractHOB;
+ } else {
+ assert lbits != 0L : lbits; // doubleToBigInt(0.0)
+ binexp +=1;
+ while ( (lbits & fractHOB ) == 0L){
+ lbits <<= 1;
+ binexp -= 1;
+ }
+ }
+ binexp -= expBias;
+ int nbits = countBits( lbits );
+ /*
+ * We now know where the high-order 1 bit is,
+ * and we know how many there are.
+ */
+ int lowOrderZeros = expShift+1-nbits;
+ lbits >>>= lowOrderZeros;
+
+ bigIntExp = binexp+1-nbits;
+ bigIntNBits = nbits;
+ return new OldFDBigIntForTest( lbits );
+ }
+
+ /*
+ * 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
+ * has already been done. Exceptional cases have already been
+ * stripped out.
+ * In particular:
+ * lvalue is a finite number (not Inf, nor NaN)
+ * lvalue > 0L (not zero, nor negative).
+ *
+ * The only reason that we develop the digits here, rather than
+ * calling on Long.toString() is that we can do it a little faster,
+ * and besides want to treat trailing 0s specially. If Long.toString
+ * changes, we should re-evaluate this strategy!
+ */
+ private void
+ developLongDigits( int decExponent, long lvalue, long insignificant ){
+ char digits[];
+ int ndigits;
+ int digitno;
+ int c;
+ //
+ // Discard non-significant low-order bits, while rounding,
+ // up to insignificant value.
+ int i;
+ for ( i = 0; insignificant >= 10L; i++ )
+ insignificant /= 10L;
+ if ( i != 0 ){
+ long pow10 = long5pow[i] << i; // 10^i == 5^i * 2^i;
+ long residue = lvalue % pow10;
+ lvalue /= pow10;
+ decExponent += i;
+ if ( residue >= (pow10>>1) ){
+ // round up based on the low-order bits we're discarding
+ lvalue++;
+ }
+ }
+ if ( lvalue <= Integer.MAX_VALUE ){
+ assert lvalue > 0L : lvalue; // lvalue <= 0
+ // even easier subcase!
+ // can do int arithmetic rather than long!
+ int ivalue = (int)lvalue;
+ ndigits = 10;
+ digits = perThreadBuffer.get();
+ digitno = ndigits-1;
+ 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 )
+ // but using long arithmetic.
+ ndigits = 20;
+ digits = perThreadBuffer.get();
+ digitno = ndigits-1;
+ 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');
+ }
+ char result [];
+ ndigits -= digitno;
+ result = new char[ ndigits ];
+ System.arraycopy( digits, digitno, result, 0, ndigits );
+ this.digits = result;
+ this.decExponent = decExponent+1;
+ this.nDigits = ndigits;
+ }
+
+ //
+ // 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;
+ int q = digits[ i = (nDigits-1)];
+ if ( q == '9' ){
+ while ( q == '9' && i > 0 ){
+ digits[i] = '0';
+ q = digits[--i];
+ }
+ if ( q == '9' ){
+ // carryout! High-order 1, rest 0s, larger exp.
+ decExponent += 1;
+ digits[0] = '1';
+ return;
+ }
+ // else fall through.
+ }
+ digits[i] = (char)(q+1);
+ decimalDigitsRoundedUp = true;
+ }
+
+ public boolean digitsRoundedUp() {
+ return decimalDigitsRoundedUp;
+ }
+
+ /*
+ * FIRST IMPORTANT CONSTRUCTOR: DOUBLE
+ */
+ public OldFloatingDecimalForTest( double d )
+ {
+ long dBits = Double.doubleToLongBits( d );
+ long fractBits;
+ int binExp;
+ int nSignificantBits;
+
+ // discover and delete sign
+ if ( (dBits&signMask) != 0 ){
+ isNegative = true;
+ dBits ^= signMask;
+ } else {
+ isNegative = false;
+ }
+ // Begin to unpack
+ // Discover obvious special cases of NaN and Infinity.
+ binExp = (int)( (dBits&expMask) >> expShift );
+ fractBits = dBits&fractMask;
+ if ( binExp == (int)(expMask>>expShift) ) {
+ isExceptional = true;
+ if ( fractBits == 0L ){
+ digits = infinity;
+ } else {
+ digits = notANumber;
+ isNegative = false; // NaN has no sign!
+ }
+ nDigits = digits.length;
+ return;
+ }
+ isExceptional = false;
+ // Finish unpacking
+ // Normalize denormalized numbers.
+ // Insert assumed high-order bit for normalized numbers.
+ // Subtract exponent bias.
+ if ( binExp == 0 ){
+ if ( fractBits == 0L ){
+ // not a denorm, just a 0!
+ decExponent = 0;
+ digits = zero;
+ nDigits = 1;
+ return;
+ }
+ while ( (fractBits&fractHOB) == 0L ){
+ fractBits <<= 1;
+ binExp -= 1;
+ }
+ nSignificantBits = expShift + binExp +1; // recall binExp is - shift count.
+ binExp += 1;
+ } else {
+ fractBits |= fractHOB;
+ nSignificantBits = expShift+1;
+ }
+ binExp -= expBias;
+ // call the routine that actually does all the hard work.
+ dtoa( binExp, fractBits, nSignificantBits );
+ }
+
+ /*
+ * SECOND IMPORTANT CONSTRUCTOR: SINGLE
+ */
+ public OldFloatingDecimalForTest( float f )
+ {
+ int fBits = Float.floatToIntBits( f );
+ int fractBits;
+ int binExp;
+ int nSignificantBits;
+
+ // discover and delete sign
+ if ( (fBits&singleSignMask) != 0 ){
+ isNegative = true;
+ fBits ^= singleSignMask;
+ } else {
+ isNegative = false;
+ }
+ // Begin to unpack
+ // Discover obvious special cases of NaN and Infinity.
+ binExp = (fBits&singleExpMask) >> singleExpShift;
+ fractBits = fBits&singleFractMask;
+ if ( binExp == (singleExpMask>>singleExpShift) ) {
+ isExceptional = true;
+ if ( fractBits == 0L ){
+ digits = infinity;
+ } else {
+ digits = notANumber;
+ isNegative = false; // NaN has no sign!
+ }
+ nDigits = digits.length;
+ return;
+ }
+ isExceptional = false;
+ // Finish unpacking
+ // Normalize denormalized numbers.
+ // Insert assumed high-order bit for normalized numbers.
+ // Subtract exponent bias.
+ if ( binExp == 0 ){
+ if ( fractBits == 0 ){
+ // not a denorm, just a 0!
+ decExponent = 0;
+ digits = zero;
+ nDigits = 1;
+ return;
+ }
+ while ( (fractBits&singleFractHOB) == 0 ){
+ fractBits <<= 1;
+ binExp -= 1;
+ }
+ nSignificantBits = singleExpShift + binExp +1; // recall binExp is - shift count.
+ binExp += 1;
+ } else {
+ fractBits |= singleFractHOB;
+ nSignificantBits = singleExpShift+1;
+ }
+ binExp -= singleExpBias;
+ // call the routine that actually does all the hard work.
+ dtoa( binExp, ((long)fractBits)<<(expShift-singleExpShift), nSignificantBits );
+ }
+
+ private void
+ dtoa( int binExp, long fractBits, int nSignificantBits )
+ {
+ int nFractBits; // number of significant bits of fractBits;
+ int nTinyBits; // number of these to the right of the point.
+ int decExp;
+
+ // Examine number. Determine if it is an easy case,
+ // which we can do pretty trivially using float/long conversion,
+ // or whether we must do real work.
+ nFractBits = countBits( fractBits );
+ nTinyBits = Math.max( 0, nFractBits - binExp - 1 );
+ if ( binExp <= maxSmallBinExp && binExp >= minSmallBinExp ){
+ // Look more closely at the number to decide if,
+ // with scaling by 10^nTinyBits, the result will fit in
+ // a long.
+ if ( (nTinyBits < long5pow.length) && ((nFractBits + n5bits[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 expShift-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.
+ */
+ long halfULP;
+ if ( nTinyBits == 0 ) {
+ if ( binExp > nSignificantBits ){
+ halfULP = 1L << ( binExp-nSignificantBits-1);
+ } else {
+ halfULP = 0L;
+ }
+ if ( binExp >= expShift ){
+ fractBits <<= (binExp-expShift);
+ } else {
+ fractBits >>>= (expShift-binExp) ;
+ }
+ developLongDigits( 0, fractBits, halfULP );
+ 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 >>>= expShift+1-nFractBits;
+ * fractBits *= long5pow[ nTinyBits ];
+ * halfULP = long5pow[ nTinyBits ] >> (1+nSignificantBits-nFractBits);
+ * developLongDigits( -nTinyBits, fractBits, 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.
+ */
+
+ /*
+ * Estimate decimal exponent. (If it is small-ish,
+ * we could double-check.)
+ *
+ * First, scale the mantissa bits such that 1 <= d2 < 2.
+ * We are then going to estimate
+ * log10(d2) ~=~ (d2-1.5)/1.5 + log(1.5)
+ * and so we can estimate
+ * log10(d) ~=~ log10(d2) + binExp * log10(2)
+ * take the floor and call it decExp.
+ * FIXME -- use more precise constants here. It costs no more.
+ */
+ double d2 = Double.longBitsToDouble(
+ expOne | ( fractBits &~ fractHOB ) );
+ decExp = (int)Math.floor(
+ (d2-1.5D)*0.289529654D + 0.176091259 + (double)binExp * 0.301029995663981 );
+ int B2, B5; // powers of 2 and powers of 5, respectively, in B
+ int S2, S5; // powers of 2 and powers of 5, respectively, in S
+ int M2, M5; // powers of 2 and powers of 5, respectively, in M
+ int Bbits; // binary digits needed to represent B, approx.
+ int tenSbits; // binary digits needed to represent 10*S, approx.
+ OldFDBigIntForTest Sval, Bval, Mval;
+
+ 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 (expShift+1-nFractBits) zeros. In the interest of compactness,
+ * I will shift out those zeros before turning fractBits into a
+ * OldFDBigIntForTest. The resulting whole number will be
+ * d * 2^(nFractBits-1-binExp).
+ */
+ fractBits >>>= (expShift+1-nFractBits);
+ 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,
+ // we must scale the other values up.
+ 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.
+ */
+ char digits[] = this.digits = new char[18];
+ 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 OldFDBigIntForTest arithmetic.
+ * We use the same algorithms, except that we "normalize"
+ * our OldFDBigIntForTests 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.
+ */
+ Bbits = nFractBits + B2 + (( B5 < n5bits.length )? n5bits[B5] : ( B5*3 ));
+ tenSbits = S2+1 + (( (S5+1) < n5bits.length )? n5bits[(S5+1)] : ( (S5+1)*3 ));
+ if ( Bbits < 64 && tenSbits < 64){
+ if ( Bbits < 32 && tenSbits < 32){
+ // wa-hoo! They're all ints!
+ int b = ((int)fractBits * small5pow[B5] ) << B2;
+ int s = small5pow[S5] << S2;
+ int m = small5pow[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; // excessively large digit
+ if ( (q == 0) && ! high ){
+ // oops. Usually ignore leading zero.
+ 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 ( decExp < -3 || decExp >= 8 ){
+ high = low = false;
+ }
+ while( ! low && ! high ){
+ q = b / s;
+ b = 10 * ( b % s );
+ m *= 10;
+ assert q < 10 : q; // excessively large digit
+ 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
+ // either!
+ low = true;
+ high = true;
+ }
+ digits[ndigit++] = (char)('0' + q);
+ }
+ lowDigitDifference = (b<<1) - tens;
+ exactDecimalConversion = (b == 0);
+ } else {
+ // still good! they're all longs!
+ long b = (fractBits * long5pow[B5] ) << B2;
+ long s = long5pow[S5] << S2;
+ long m = long5pow[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; // excessively large digit
+ if ( (q == 0) && ! high ){
+ // oops. Usually ignore leading zero.
+ 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 ( decExp < -3 || decExp >= 8 ){
+ high = low = false;
+ }
+ while( ! low && ! high ){
+ q = (int) ( b / s );
+ b = 10 * ( b % s );
+ m *= 10;
+ assert q < 10 : q; // excessively large digit
+ 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
+ // either!
+ low = true;
+ high = true;
+ }
+ digits[ndigit++] = (char)('0' + q);
+ }
+ lowDigitDifference = (b<<1) - tens;
+ exactDecimalConversion = (b == 0);
+ }
+ } else {
+ OldFDBigIntForTest ZeroVal = new OldFDBigIntForTest(0);
+ OldFDBigIntForTest tenSval;
+ int shiftBias;
+
+ /*
+ * We really must do OldFDBigIntForTest arithmetic.
+ * Fist, construct our OldFDBigIntForTest initial values.
+ */
+ Bval = multPow52( new OldFDBigIntForTest( fractBits ), B5, B2 );
+ Sval = constructPow52( S5, S2 );
+ Mval = constructPow52( M5, M2 );
+
+
+ // normalize so that division works better
+ Bval.lshiftMe( shiftBias = Sval.normalizeMe() );
+ Mval.lshiftMe( shiftBias );
+ tenSval = Sval.mult( 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 = Bval.quoRemIteration( Sval );
+ Mval = Mval.mult( 10 );
+ low = (Bval.cmp( Mval ) < 0);
+ high = (Bval.add( Mval ).cmp( tenSval ) > 0 );
+ assert q < 10 : q; // excessively large digit
+ if ( (q == 0) && ! high ){
+ // oops. Usually ignore leading zero.
+ 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 ( decExp < -3 || decExp >= 8 ){
+ high = low = false;
+ }
+ while( ! low && ! high ){
+ q = Bval.quoRemIteration( Sval );
+ Mval = Mval.mult( 10 );
+ assert q < 10 : q; // excessively large digit
+ low = (Bval.cmp( Mval ) < 0);
+ high = (Bval.add( Mval ).cmp( tenSval ) > 0 );
+ digits[ndigit++] = (char)('0' + q);
+ }
+ if ( high && low ){
+ Bval.lshiftMe(1);
+ lowDigitDifference = Bval.cmp(tenSval);
+ } else {
+ lowDigitDifference = 0L; // this here only for flow analysis!
+ }
+ exactDecimalConversion = (Bval.cmp( ZeroVal ) == 0);
+ }
+ this.decExponent = decExp+1;
+ this.digits = digits;
+ this.nDigits = ndigit;
+ /*
+ * Last digit gets rounded based on stopping condition.
+ */
+ if ( high ){
+ if ( low ){
+ if ( lowDigitDifference == 0L ){
+ // it's a tie!
+ // choose based on which digits we like.
+ if ( (digits[nDigits-1]&1) != 0 ) roundup();
+ } else if ( lowDigitDifference > 0 ){
+ roundup();
+ }
+ } else {
+ roundup();
+ }
+ }
+ }
+
+ public boolean decimalDigitsExact() {
+ return exactDecimalConversion;
+ }
+
+ public String
+ toString(){
+ // most brain-dead version
+ StringBuffer result = new StringBuffer( nDigits+8 );
+ if ( isNegative ){ result.append( '-' ); }
+ if ( isExceptional ){
+ result.append( digits, 0, nDigits );
+ } else {
+ result.append( "0.");
+ result.append( digits, 0, nDigits );
+ result.append('e');
+ result.append( decExponent );
+ }
+ return new String(result);
+ }
+
+ public String toJavaFormatString() {
+ char result[] = perThreadBuffer.get();
+ int i = getChars(result);
+ return new String(result, 0, i);
+ }
+
+ private int getChars(char[] result) {
+ assert nDigits <= 19 : nDigits; // generous bound on size of nDigits
+ int i = 0;
+ if (isNegative) { result[0] = '-'; i = 1; }
+ if (isExceptional) {
+ System.arraycopy(digits, 0, result, i, nDigits);
+ i += nDigits;
+ } else {
+ if (decExponent > 0 && decExponent < 8) {
+ // print digits.digits.
+ int charLength = Math.min(nDigits, decExponent);
+ System.arraycopy(digits, 0, result, i, charLength);
+ i += charLength;
+ if (charLength < decExponent) {
+ charLength = decExponent-charLength;
+ System.arraycopy(zero, 0, result, i, charLength);
+ i += charLength;
+ result[i++] = '.';
+ result[i++] = '0';
+ } else {
+ result[i++] = '.';
+ if (charLength < nDigits) {
+ int t = nDigits - charLength;
+ System.arraycopy(digits, charLength, result, i, t);
+ i += t;
+ } else {
+ result[i++] = '0';
+ }
+ }
+ } else if (decExponent <=0 && decExponent > -3) {
+ result[i++] = '0';
+ result[i++] = '.';
+ if (decExponent != 0) {
+ System.arraycopy(zero, 0, result, i, -decExponent);
+ i -= decExponent;
+ }
+ System.arraycopy(digits, 0, result, i, nDigits);
+ i += nDigits;
+ } else {
+ result[i++] = digits[0];
+ result[i++] = '.';
+ if (nDigits > 1) {
+ System.arraycopy(digits, 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;
+ }
+ // decExponent has 1, 2, or 3, digits
+ 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;
+ }
+
+ // Per-thread buffer for string/stringbuffer conversion
+ private static ThreadLocal<char[]> perThreadBuffer = new ThreadLocal<char[]>() {
+ protected synchronized char[] initialValue() {
+ return new char[26];
+ }
+ };
+
+ public void appendTo(Appendable buf) {
+ char result[] = perThreadBuffer.get();
+ int i = getChars(result);
+ if (buf instanceof StringBuilder)
+ ((StringBuilder) buf).append(result, 0, i);
+ else if (buf instanceof StringBuffer)
+ ((StringBuffer) buf).append(result, 0, i);
+ else
+ assert false;
+ }
+
+ @SuppressWarnings("fallthrough")
+ public static OldFloatingDecimalForTest
+ readJavaFormatString( String in ) throws NumberFormatException {
+ boolean isNegative = false;
+ boolean signSeen = false;
+ int decExp;
+ char c;
+
+ parseNumber:
+ try{
+ in = in.trim(); // don't fool around with white space.
+ // throws NullPointerException if null
+ int l = in.length();
+ if ( l == 0 ) throw new NumberFormatException("empty String");
+ int i = 0;
+ switch ( c = in.charAt( i ) ){
+ case '-':
+ isNegative = true;
+ //FALLTHROUGH
+ case '+':
+ i++;
+ signSeen = true;
+ }
+
+ // Check for NaN and Infinity strings
+ c = in.charAt(i);
+ if(c == 'N' || c == 'I') { // possible NaN or infinity
+ boolean potentialNaN = false;
+ char targetChars[] = null; // char array of "NaN" or "Infinity"
+
+ if(c == 'N') {
+ targetChars = notANumber;
+ potentialNaN = true;
+ } else {
+ targetChars = infinity;
+ }
+
+ // compare Input string to "NaN" or "Infinity"
+ int j = 0;
+ while(i < l && j < targetChars.length) {
+ if(in.charAt(i) == targetChars[j]) {
+ i++; j++;
+ }
+ else // something is amiss, throw exception
+ break parseNumber;
+ }
+
+ // For the candidate string to be a NaN or infinity,
+ // all characters in input string and target char[]
+ // must be matched ==> j must equal targetChars.length
+ // and i must equal l
+ if( (j == targetChars.length) && (i == l) ) { // return NaN or infinity
+ return (potentialNaN ? new OldFloatingDecimalForTest(Double.NaN) // NaN has no sign
+ : new OldFloatingDecimalForTest(isNegative?
+ Double.NEGATIVE_INFINITY:
+ Double.POSITIVE_INFINITY)) ;
+ }
+ else { // something went wrong, throw exception
+ break parseNumber;
+ }
+
+ } else if (c == '0') { // check for hexadecimal floating-point number
+ if (l > i+1 ) {
+ char ch = in.charAt(i+1);
+ if (ch == 'x' || ch == 'X' ) // possible hex string
+ return parseHexString(in);
+ }
+ } // look for and process decimal floating-point string
+
+ char[] digits = new char[ l ];
+ int nDigits= 0;
+ boolean decSeen = false;
+ int decPt = 0;
+ int nLeadZero = 0;
+ int nTrailZero= 0;
+ digitLoop:
+ while ( i < l ){
+ switch ( c = in.charAt( i ) ){
+ case '0':
+ if ( nDigits > 0 ){
+ nTrailZero += 1;
+ } else {
+ nLeadZero += 1;
+ }
+ break; // out of switch.
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ while ( nTrailZero > 0 ){
+ digits[nDigits++] = '0';
+ nTrailZero -= 1;
+ }
+ digits[nDigits++] = c;
+ break; // out of switch.
+ case '.':
+ if ( decSeen ){
+ // already saw one ., this is the 2nd.
+ throw new NumberFormatException("multiple points");
+ }
+ decPt = i;
+ if ( signSeen ){
+ decPt -= 1;
+ }
+ decSeen = true;
+ break; // out of switch.
+ default:
+ break digitLoop;
+ }
+ i++;
+ }
+ /*
+ * 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!
+ */
+ if ( nDigits == 0 ){
+ digits = zero;
+ nDigits = 1;
+ if ( nLeadZero == 0 ){
+ // we saw NO DIGITS AT ALL,
+ // not even a crummy 0!
+ // this is not allowed.
+ break parseNumber; // go throw exception
+ }
+
+ }
+
+ /* 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 < l) && (((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;
+ //FALLTHROUGH
+ case '+':
+ i++;
+ }
+ int expAt = i;
+ expLoop:
+ while ( i < l ){
+ if ( expVal >= reallyBig ){
+ // the next character will cause integer
+ // overflow.
+ expOverflow = true;
+ }
+ switch ( c = in.charAt(i++) ){
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ expVal = expVal*10 + ( (int)c - (int)'0' );
+ continue;
+ default:
+ i--; // back up.
+ break expLoop; // stop parsing exponent.
+ }
+ }
+ int expLimit = bigDecimalExponent+nDigits+nTrailZero;
+ if ( expOverflow || ( expVal > expLimit ) ){
+ //
+ // 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
+ // for expVal > (MAX+N), where N >= abs(decExp)
+ 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.
+ // HUMBUG
+ if ( i == expAt )
+ break parseNumber; // certainly bad
+ }
+ /*
+ * We parsed everything we could.
+ * If there are leftovers, then this is not good input!
+ */
+ if ( i < l &&
+ ((i != l - 1) ||
+ (in.charAt(i) != 'f' &&
+ in.charAt(i) != 'F' &&
+ in.charAt(i) != 'd' &&
+ in.charAt(i) != 'D'))) {
+ break parseNumber; // go throw exception
+ }
+
+ return new OldFloatingDecimalForTest( isNegative, decExp, digits, nDigits, false );
+ } catch ( StringIndexOutOfBoundsException e ){ }
+ throw new NumberFormatException("For input string: \"" + in + "\"");
+ }
+
+ /*
+ * Take a FloatingDecimal, 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 OldFDBigIntForTest arithmetic.
+ * Formulate the EXACT big-number result as
+ * bigD0 * 10^exp
+ */
+ OldFDBigIntForTest bigD0 = new OldFDBigIntForTest( lValue, digits, kDigits, nDigits );
+ exp = decExponent - nDigits;
+
+ correctionLoop:
+ while(true){
+ /* AS A SIDE EFFECT, THIS METHOD WILL SET THE INSTANCE VARIABLES
+ * bigIntExp and bigIntNBits
+ */
+ OldFDBigIntForTest bigB = doubleToBigInt( dValue );
+
+ /*
+ * 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; // 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 );
+ OldFDBigIntForTest bigD = multPow52( new OldFDBigIntForTest( 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.
+ //
+ OldFDBigIntForTest 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+1) ){
+ // 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 frequency
+ break correctionLoop;
+ }
+ OldFDBigIntForTest 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 FloatingDecimal, 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 conversion
+ * 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
+ * algorithm 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,
+ 5*5,
+ 5*5*5,
+ 5*5*5*5,
+ 5*5*5*5*5,
+ 5*5*5*5*5*5,
+ 5*5*5*5*5*5*5,
+ 5*5*5*5*5*5*5*5,
+ 5*5*5*5*5*5*5*5*5,
+ 5*5*5*5*5*5*5*5*5*5,
+ 5*5*5*5*5*5*5*5*5*5*5,
+ 5*5*5*5*5*5*5*5*5*5*5*5,
+ 5*5*5*5*5*5*5*5*5*5*5*5*5
+ };
+
+
+ private static final long long5pow[] = {
+ 1L,
+ 5L,
+ 5L*5,
+ 5L*5*5,
+ 5L*5*5*5,
+ 5L*5*5*5*5,
+ 5L*5*5*5*5*5,
+ 5L*5*5*5*5*5*5,
+ 5L*5*5*5*5*5*5*5,
+ 5L*5*5*5*5*5*5*5*5,
+ 5L*5*5*5*5*5*5*5*5*5,
+ 5L*5*5*5*5*5*5*5*5*5*5,
+ 5L*5*5*5*5*5*5*5*5*5*5*5,
+ 5L*5*5*5*5*5*5*5*5*5*5*5*5,
+ 5L*5*5*5*5*5*5*5*5*5*5*5*5*5,
+ 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
+ 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
+ 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
+ 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
+ 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
+ 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
+ 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
+ 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
+ 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
+ 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
+ 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
+ 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
+ };
+
+ // approximately ceil( log2( long5pow[i] ) )
+ private static final int n5bits[] = {
+ 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 static final char infinity[] = { 'I', 'n', 'f', 'i', 'n', 'i', 't', 'y' };
+ private static final char notANumber[] = { 'N', 'a', 'N' };
+ private static final char zero[] = { '0', '0', '0', '0', '0', '0', '0', '0' };
+
+
+ /*
+ * Grammar is compatible with hexadecimal floating-point constants
+ * described in section 6.4.4.2 of the C99 specification.
+ */
+ private static Pattern hexFloatPattern = null;
+ private static synchronized Pattern getHexFloatPattern() {
+ if (hexFloatPattern == null) {
+ hexFloatPattern = Pattern.compile(
+ //1 234 56 7 8 9
+ "([-+])?0[xX](((\\p{XDigit}+)\\.?)|((\\p{XDigit}*)\\.(\\p{XDigit}+)))[pP]([-+])?(\\p{Digit}+)[fFdD]?"
+ );
+ }
+ return hexFloatPattern;
+ }
+
+ /*
+ * Convert string s to a suitable floating decimal; uses the
+ * double constructor and set the roundDir variable appropriately
+ * in case the value is later converted to a float.
+ */
+ static OldFloatingDecimalForTest parseHexString(String s) {
+ // Verify string is a member of the hexadecimal floating-point
+ // string language.
+ Matcher m = getHexFloatPattern().matcher(s);
+ boolean validInput = m.matches();
+
+ if (!validInput) {
+ // Input does not match pattern
+ 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.
+ */
+
+ // Extract significand sign
+ String group1 = m.group(1);
+ double sign = (( group1 == null ) || group1.equals("+"))? 1.0 : -1.0;
+
+
+ // 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; // number of meaningful digits to
+ // left of "decimal" point
+ // (leading zeros stripped)
+ int rightDigits = 0; // number of digits to right of
+ // "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
+ // Leading zeros never matter on the integer portion
+ significandString = stripLeadingZeros(group4);
+ leftDigits = significandString.length();
+ }
+ else {
+ // Group 6 is the optional integer; leading zeros
+ // never matter on the integer portion
+ String group6 = stripLeadingZeros(m.group(6));
+ leftDigits = group6.length();
+
+ // fraction
+ String group7 = m.group(7);
+ rightDigits = group7.length();
+
+ // Turn "integer.fraction" into "integer"+"fraction"
+ significandString =
+ ((group6 == null)?"":group6) + // is the null
+ // check necessary?
+ group7;
+ }
+
+ significandString = stripLeadingZeros(significandString);
+ signifLength = significandString.length();
+
+ /*
+ * Adjust exponent as described above
+ */
+ if (leftDigits >= 1) { // Cases 1 and 2
+ exponentAdjust = 4*(leftDigits - 1);
+ } else { // Cases 3 and 4
+ exponentAdjust = -4*( rightDigits - signifLength + 1);
+ }
+
+ // If the significand is zero, the exponent doesn't
+ // matter; return a properly signed zero.
+
+ if (signifLength == 0) { // Only zeros in input
+ return new OldFloatingDecimalForTest(sign * 0.0);
+ }
+ }
+
+ // 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
+ // - +0.0 -0.0
+ return new OldFloatingDecimalForTest(sign * (positiveExponent ?
+ Double.POSITIVE_INFINITY : 0.0));
+ }
+
+ long rawExponent =
+ (positiveExponent ? 1L : -1L) * // exponent sign
+ unsignedRawExponent; // exponent magnitude
+
+ // Calculate partially adjusted exponent
+ 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 bitsCopied=0;
+ 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
+ // surprising shift semantics!
+ 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) { // [2, 3]
+ significand |= leadingDigit << 51;
+ nextShift = 52 - 5;
+ exponent += 1;
+ }
+ else if (leadingDigit <= 7) { // [4, 7]
+ significand |= leadingDigit << 50;
+ nextShift = 52 - 6;
+ exponent += 2;
+ }
+ else if (leadingDigit <= 15) { // [8, f]
+ 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
+ // hex digits.
+ 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 ) { // at least one hex input digit exists
+ long currentDigit = getHexDigit(significandString, i);
+
+ // from nextShift, figure out how many bits need
+ // to be copied, if any
+ switch(nextShift) { // must be negative
+ case -1:
+ // three bits need to be copied in; can
+ // set round bit
+ significand |= ((currentDigit & 0xEL) >> 1);
+ round = (currentDigit & 0x1L) != 0L;
+ break;
+
+ case -2:
+ // two bits need to be copied in; can
+ // set round and start sticky
+ significand |= ((currentDigit & 0xCL) >> 2);
+ round = (currentDigit &0x2L) != 0L;
+ sticky = (currentDigit & 0x1L) != 0;
+ break;
+
+ case -3:
+ // one bit needs to be copied in
+ significand |= ((currentDigit & 0x8L)>>3);
+ // Now set round and start sticky, if possible
+ 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); // is top bit set?
+ // nonzeros in three low order bits?
+ 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
+ // the remaining unprocessed input.
+ 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.
+
+
+ // Check for overflow and update exponent accordingly.
+
+ if (exponent > DoubleConsts.MAX_EXPONENT) { // Infinite result
+ // overflow to properly signed infinity
+ return new OldFloatingDecimalForTest(sign * Double.POSITIVE_INFINITY);
+ } else { // Finite return value
+ if (exponent <= DoubleConsts.MAX_EXPONENT && // (Usually) normal result
+ exponent >= DoubleConsts.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 < DoubleConsts.MIN_EXPONENT)
+
+ if (exponent < (DoubleConsts.MIN_SUB_EXPONENT -1 )) {
+ // No way to round back to nonzero value
+ // regardless of significand if the exponent is
+ // less than -1075.
+ return new OldFloatingDecimalForTest(sign * 0.0);
+ } 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:
+ // First, isolate the new round bit
+ round = (significand & (1L << (bitsDiscarded -1))) != 0L;
+ if (bitsDiscarded > 1) {
+ // create mask to update sticky bits; low
+ // order bitsDiscarded bits should be 1
+ long mask = ~((~0L) << (bitsDiscarded -1));
+ sticky = sticky || ((significand & mask) != 0L ) ;
+ }
+
+ // Now, discard the bits
+ significand = significand >> bitsDiscarded;
+
+ significand = (( ((long)(DoubleConsts.MIN_EXPONENT -1) + // subnorm exp.
+ (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 incremented = false;
+ boolean leastZero = ((significand & 1L) == 0L);
+ if( ( leastZero && round && sticky ) ||
+ ((!leastZero) && round )) {
+ incremented = true;
+ significand++;
+ }
+
+ OldFloatingDecimalForTest fd = new OldFloatingDecimalForTest(Math.copySign(
+ Double.longBitsToDouble(significand),
+ sign));
+
+ /*
+ * Set roundingDir variable field of fd properly so
+ * that the input string can be properly rounded to a
+ * float value. There are two cases to consider:
+ *
+ * 1. rounding to double discards sticky bit
+ * information that would change the result of a float
+ * rounding (near halfway case between two floats)
+ *
+ * 2. rounding to double rounds up when rounding up
+ * would not occur when rounding to float.
+ *
+ * For former case only needs to be considered when
+ * the bits rounded away when casting to float are all
+ * zero; otherwise, float round bit is properly set
+ * and sticky will already be true.
+ *
+ * The lower exponent bound for the code below is the
+ * minimum (normalized) subnormal exponent - 1 since a
+ * value with that exponent can round up to the
+ * minimum subnormal value and the sticky bit
+ * information must be preserved (i.e. case 1).
+ */
+ if ((exponent >= FloatConsts.MIN_SUB_EXPONENT-1) &&
+ (exponent <= FloatConsts.MAX_EXPONENT ) ){
+ // Outside above exponent range, the float value
+ // will be zero or infinity.
+
+ /*
+ * If the low-order 28 bits of a rounded double
+ * significand are 0, the double could be a
+ * half-way case for a rounding to float. If the
+ * double value is a half-way case, the double
+ * significand may have to be modified to round
+ * the the right float value (see the stickyRound
+ * method). If the rounding to double has lost
+ * what would be float sticky bit information, the
+ * double significand must be incremented. If the
+ * double value's significand was itself
+ * incremented, the float value may end up too
+ * large so the increment should be undone.
+ */
+ if ((significand & 0xfffffffL) == 0x0L) {
+ // For negative values, the sign of the
+ // roundDir is the same as for positive values
+ // since adding 1 increasing the significand's
+ // magnitude and subtracting 1 decreases the
+ // significand's magnitude. If neither round
+ // nor sticky is true, the double value is
+ // exact and no adjustment is required for a
+ // proper float rounding.
+ if( round || sticky) {
+ if (leastZero) { // prerounding lsb is 0
+ // If round and sticky were both true,
+ // and the least significant
+ // significand bit were 0, the rounded
+ // significand would not have its
+ // low-order bits be zero. Therefore,
+ // we only need to adjust the
+ // significand if round XOR sticky is
+ // true.
+ if (round ^ sticky) {
+ fd.roundDir = 1;
+ }
+ }
+ else { // prerounding lsb is 1
+ // If the prerounding lsb is 1 and the
+ // resulting significand has its
+ // low-order bits zero, the significand
+ // was incremented. Here, we undo the
+ // increment, which will ensure the
+ // right guard and sticky bits for the
+ // float rounding.
+ if (round)
+ fd.roundDir = -1;
+ }
+ }
+ }
+ }
+
+ fd.fromHex = true;
+ return fd;
+ }
+ }
+ }
+
+ /**
+ * Return <code>s</code> with any leading zeros removed.
+ */
+ static String stripLeadingZeros(String s) {
+ return s.replaceFirst("^0+", "");
+ }
+
+ /**
+ * Extract a hexadecimal digit from position <code>position</code>
+ * of string <code>s</code>.
+ */
+ 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;
+ }
+
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/misc/FloatingDecimal/TestFDBigInteger.java Wed Jun 05 21:01:02 2013 -0700
@@ -0,0 +1,426 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.math.BigInteger;
+import java.util.Random;
+import sun.misc.FDBigInteger;
+
+/**
+ * @test
+ * @bug 7032154
+ * @summary unit testys of sun.misc.FDBigInteger
+ * @author Dmitry Nadezhin
+ */
+public class TestFDBigInteger {
+
+ private static final int MAX_P5 = 413;
+ private static final int MAX_P2 = 65;
+ private static final long LONG_SIGN_MASK = (1L << 63);
+ private static final BigInteger FIVE = BigInteger.valueOf(5);
+ private static final FDBigInteger MUTABLE_ZERO = FDBigInteger.valueOfPow52(0, 0).leftInplaceSub(FDBigInteger.valueOfPow52(0, 0));
+ private static final FDBigInteger IMMUTABLE_ZERO = FDBigInteger.valueOfPow52(0, 0).leftInplaceSub(FDBigInteger.valueOfPow52(0, 0));
+ private static final FDBigInteger IMMUTABLE_MILLION = genMillion1();
+ private static final FDBigInteger IMMUTABLE_BILLION = genBillion1();
+ private static final FDBigInteger IMMUTABLE_TEN18 = genTen18();
+
+ static {
+ IMMUTABLE_ZERO.makeImmutable();
+ IMMUTABLE_MILLION.makeImmutable();
+ IMMUTABLE_BILLION.makeImmutable();
+ IMMUTABLE_TEN18.makeImmutable();
+ }
+
+ private static FDBigInteger mutable(String hex, int offset) {
+ char[] chars = new BigInteger(hex, 16).toString().toCharArray();
+ return new FDBigInteger(0, chars, 0, chars.length).multByPow52(0, offset * 32);
+ }
+
+ private static FDBigInteger immutable(String hex, int offset) {
+ FDBigInteger fd = mutable(hex, offset);
+ fd.makeImmutable();
+ return fd;
+ }
+
+ private static BigInteger biPow52(int p5, int p2) {
+ return FIVE.pow(p5).shiftLeft(p2);
+ }
+
+ // data.length == 1, nWords == 1, offset == 0
+ private static FDBigInteger genMillion1() {
+ return FDBigInteger.valueOfPow52(6, 0).leftShift(6);
+ }
+
+ // data.length == 2, nWords == 1, offset == 0
+ private static FDBigInteger genMillion2() {
+ return FDBigInteger.valueOfMulPow52(1000000L, 0, 0);
+ }
+
+ // data.length == 1, nWords == 1, offset == 0
+ private static FDBigInteger genBillion1() {
+ return FDBigInteger.valueOfPow52(9, 0).leftShift(9);
+ }
+
+ // data.length == 2, nWords == 2, offset == 0
+ private static FDBigInteger genTen18() {
+ return FDBigInteger.valueOfPow52(18, 0).leftShift(18);
+ }
+
+ private static void check(BigInteger expected, FDBigInteger actual, String message) throws Exception {
+ if (!expected.equals(actual.toBigInteger())) {
+ throw new Exception(message + " result " + actual.toHexString() + " expected " + expected.toString(16));
+ }
+ }
+
+ private static void testValueOfPow52(int p5, int p2) throws Exception {
+ check(biPow52(p5, p2), FDBigInteger.valueOfPow52(p5, p2),
+ "valueOfPow52(" + p5 + "," + p2 + ")");
+ }
+
+ private static void testValueOfPow52() throws Exception {
+ for (int p5 = 0; p5 <= MAX_P5; p5++) {
+ for (int p2 = 0; p2 <= MAX_P2; p2++) {
+ testValueOfPow52(p5, p2);
+ }
+ }
+ }
+
+ private static void testValueOfMulPow52(long value, int p5, int p2) throws Exception {
+ BigInteger bi = BigInteger.valueOf(value & ~LONG_SIGN_MASK);
+ if (value < 0) {
+ bi = bi.setBit(63);
+ }
+ check(biPow52(p5, p2).multiply(bi), FDBigInteger.valueOfMulPow52(value, p5, p2),
+ "valueOfMulPow52(" + Long.toHexString(value) + "." + p5 + "," + p2 + ")");
+ }
+
+ private static void testValueOfMulPow52(long value, int p5) throws Exception {
+ testValueOfMulPow52(value, p5, 0);
+ testValueOfMulPow52(value, p5, 1);
+ testValueOfMulPow52(value, p5, 30);
+ testValueOfMulPow52(value, p5, 31);
+ testValueOfMulPow52(value, p5, 33);
+ testValueOfMulPow52(value, p5, 63);
+ }
+
+ private static void testValueOfMulPow52() throws Exception {
+ for (int p5 = 0; p5 <= MAX_P5; p5++) {
+ testValueOfMulPow52(0xFFFFFFFFL, p5);
+ testValueOfMulPow52(0x123456789AL, p5);
+ testValueOfMulPow52(0x7FFFFFFFFFFFFFFFL, p5);
+ testValueOfMulPow52(0xFFFFFFFFFFF54321L, p5);
+ }
+ }
+
+ private static void testLeftShift(FDBigInteger t, int shift, boolean isImmutable) throws Exception {
+ BigInteger bt = t.toBigInteger();
+ FDBigInteger r = t.leftShift(shift);
+ if ((bt.signum() == 0 || shift == 0 || !isImmutable) && r != t) {
+ throw new Exception("leftShift doesn't reuse its argument");
+ }
+ if (isImmutable) {
+ check(bt, t, "leftShift corrupts its argument");
+ }
+ check(bt.shiftLeft(shift), r, "leftShift returns wrong result");
+ }
+
+ private static void testLeftShift() throws Exception {
+ testLeftShift(IMMUTABLE_ZERO, 0, true);
+ testLeftShift(IMMUTABLE_ZERO, 10, true);
+ testLeftShift(MUTABLE_ZERO, 0, false);
+ testLeftShift(MUTABLE_ZERO, 10, false);
+
+ testLeftShift(IMMUTABLE_MILLION, 0, true);
+ testLeftShift(IMMUTABLE_MILLION, 1, true);
+ testLeftShift(IMMUTABLE_MILLION, 12, true);
+ testLeftShift(IMMUTABLE_MILLION, 13, true);
+ testLeftShift(IMMUTABLE_MILLION, 32, true);
+ testLeftShift(IMMUTABLE_MILLION, 33, true);
+ testLeftShift(IMMUTABLE_MILLION, 44, true);
+ testLeftShift(IMMUTABLE_MILLION, 45, true);
+
+ testLeftShift(genMillion1(), 0, false);
+ testLeftShift(genMillion1(), 1, false);
+ testLeftShift(genMillion1(), 12, false);
+ testLeftShift(genMillion1(), 13, false);
+ testLeftShift(genMillion1(), 25, false);
+ testLeftShift(genMillion1(), 26, false);
+ testLeftShift(genMillion1(), 32, false);
+ testLeftShift(genMillion1(), 33, false);
+ testLeftShift(genMillion1(), 44, false);
+ testLeftShift(genMillion1(), 45, false);
+
+ testLeftShift(genMillion2(), 0, false);
+ testLeftShift(genMillion2(), 1, false);
+ testLeftShift(genMillion2(), 12, false);
+ testLeftShift(genMillion2(), 13, false);
+ testLeftShift(genMillion2(), 25, false);
+ testLeftShift(genMillion2(), 26, false);
+ testLeftShift(genMillion2(), 32, false);
+ testLeftShift(genMillion2(), 33, false);
+ testLeftShift(genMillion2(), 44, false);
+ testLeftShift(genMillion2(), 45, false);
+ }
+
+ private static void testQuoRemIteration(FDBigInteger t, FDBigInteger s) throws Exception {
+ BigInteger bt = t.toBigInteger();
+ BigInteger bs = s.toBigInteger();
+ int q = t.quoRemIteration(s);
+ BigInteger[] qr = bt.divideAndRemainder(bs);
+ if (!BigInteger.valueOf(q).equals(qr[0])) {
+ throw new Exception("quoRemIteration returns incorrect quo");
+ }
+ check(qr[1].multiply(BigInteger.TEN), t, "quoRemIteration returns incorrect rem");
+ }
+
+ private static void testQuoRemIteration() throws Exception {
+ // IMMUTABLE_TEN18 == 0de0b6b3a7640000
+ // q = 0
+ testQuoRemIteration(mutable("00000001", 0), IMMUTABLE_TEN18);
+ testQuoRemIteration(mutable("00000001", 1), IMMUTABLE_TEN18);
+ testQuoRemIteration(mutable("0de0b6b2", 1), IMMUTABLE_TEN18);
+ // q = 1 -> q = 0
+ testQuoRemIteration(mutable("0de0b6b3", 1), IMMUTABLE_TEN18);
+ testQuoRemIteration(mutable("0de0b6b3a763FFFF", 0), IMMUTABLE_TEN18);
+ // q = 1
+ testQuoRemIteration(mutable("0de0b6b3a7640000", 0), IMMUTABLE_TEN18);
+ testQuoRemIteration(mutable("0de0b6b3FFFFFFFF", 0), IMMUTABLE_TEN18);
+ testQuoRemIteration(mutable("8ac72304", 1), IMMUTABLE_TEN18);
+ testQuoRemIteration(mutable("0de0b6b400000000", 0), IMMUTABLE_TEN18);
+ testQuoRemIteration(mutable("8ac72305", 1), IMMUTABLE_TEN18);
+ // q = 18
+ testQuoRemIteration(mutable("FFFFFFFF", 1), IMMUTABLE_TEN18);
+ }
+
+ private static void testCmp(FDBigInteger t, FDBigInteger o) throws Exception {
+ BigInteger bt = t.toBigInteger();
+ BigInteger bo = o.toBigInteger();
+ int cmp = t.cmp(o);
+ int bcmp = bt.compareTo(bo);
+ if (bcmp != cmp) {
+ throw new Exception("cmp returns " + cmp + " expected " + bcmp);
+ }
+ check(bt, t, "cmp corrupts this");
+ check(bo, o, "cmp corrupts other");
+ if (o.cmp(t) != -cmp) {
+ throw new Exception("asymmetrical cmp");
+ }
+ check(bt, t, "cmp corrupts this");
+ check(bo, o, "cmp corrupts other");
+ }
+
+ private static void testCmp() throws Exception {
+ testCmp(mutable("FFFFFFFF", 0), mutable("100000000", 0));
+ testCmp(mutable("FFFFFFFF", 0), mutable("1", 1));
+ testCmp(mutable("5", 0), mutable("6", 0));
+ testCmp(mutable("5", 0), mutable("5", 0));
+ testCmp(mutable("5000000001", 0), mutable("500000001", 0));
+ testCmp(mutable("5000000001", 0), mutable("6", 1));
+ testCmp(mutable("5000000001", 0), mutable("5", 1));
+ testCmp(mutable("5000000000", 0), mutable("5", 1));
+ }
+
+ private static void testCmpPow52(FDBigInteger t, int p5, int p2) throws Exception {
+ FDBigInteger o = FDBigInteger.valueOfPow52(p5, p2);
+ BigInteger bt = t.toBigInteger();
+ BigInteger bo = biPow52(p5, p2);
+ int cmp = t.cmp(o);
+ int bcmp = bt.compareTo(bo);
+ if (bcmp != cmp) {
+ throw new Exception("cmpPow52 returns " + cmp + " expected " + bcmp);
+ }
+ check(bt, t, "cmpPow52 corrupts this");
+ check(bo, o, "cmpPow5 corrupts other");
+ }
+
+ private static void testCmpPow52() throws Exception {
+ testCmpPow52(mutable("00000002", 1), 0, 31);
+ testCmpPow52(mutable("00000002", 1), 0, 32);
+ testCmpPow52(mutable("00000002", 1), 0, 33);
+ testCmpPow52(mutable("00000002", 1), 0, 34);
+ testCmpPow52(mutable("00000002", 1), 0, 64);
+ testCmpPow52(mutable("00000003", 1), 0, 32);
+ testCmpPow52(mutable("00000003", 1), 0, 33);
+ testCmpPow52(mutable("00000003", 1), 0, 34);
+ }
+
+ private static void testAddAndCmp(FDBigInteger t, FDBigInteger x, FDBigInteger y) throws Exception {
+ BigInteger bt = t.toBigInteger();
+ BigInteger bx = x.toBigInteger();
+ BigInteger by = y.toBigInteger();
+ int cmp = t.addAndCmp(x, y);
+ int bcmp = bt.compareTo(bx.add(by));
+ if (bcmp != cmp) {
+ throw new Exception("addAndCmp returns " + cmp + " expected " + bcmp);
+ }
+ check(bt, t, "addAndCmp corrupts this");
+ check(bx, x, "addAndCmp corrupts x");
+ check(by, y, "addAndCmp corrupts y");
+ }
+
+ private static void testAddAndCmp() throws Exception {
+ testAddAndCmp(MUTABLE_ZERO, MUTABLE_ZERO, MUTABLE_ZERO);
+ testAddAndCmp(mutable("00000001", 0), MUTABLE_ZERO, MUTABLE_ZERO);
+ testAddAndCmp(mutable("00000001", 0), mutable("00000001", 0), MUTABLE_ZERO);
+ testAddAndCmp(mutable("00000001", 0), MUTABLE_ZERO, mutable("00000001", 0));
+ testAddAndCmp(mutable("00000001", 0), mutable("00000002", 0), MUTABLE_ZERO);
+ testAddAndCmp(mutable("00000001", 0), MUTABLE_ZERO, mutable("00000002", 0));
+ testAddAndCmp(mutable("00000001", 2), mutable("FFFFFFFF", 0), mutable("FFFFFFFF", 0));
+ testAddAndCmp(mutable("00000001", 0), mutable("00000001", 1), mutable("00000001", 0));
+
+ testAddAndCmp(mutable("00000001", 2), mutable("0F0F0F0F80000000", 1), mutable("F0F0F0F080000000", 1));
+ testAddAndCmp(mutable("00000001", 2), mutable("0F0F0F0E80000000", 1), mutable("F0F0F0F080000000", 1));
+
+ testAddAndCmp(mutable("00000002", 1), mutable("0000000180000000", 1), mutable("0000000280000000", 1));
+ testAddAndCmp(mutable("00000003", 1), mutable("0000000180000000", 1), mutable("0000000280000000", 1));
+ testAddAndCmp(mutable("00000004", 1), mutable("0000000180000000", 1), mutable("0000000280000000", 1));
+ testAddAndCmp(mutable("00000005", 1), mutable("0000000180000000", 1), mutable("0000000280000000", 1));
+
+ testAddAndCmp(mutable("00000001", 2), mutable("8000000000000000", 0), mutable("8000000000000000", 0));
+ testAddAndCmp(mutable("00000001", 2), mutable("8000000000000000", 0), mutable("8000000000000001", 0));
+ testAddAndCmp(mutable("00000002", 2), mutable("8000000000000000", 0), mutable("8000000000000000", 0));
+ testAddAndCmp(mutable("00000003", 2), mutable("8000000000000000", 0), mutable("8000000000000000", 0));
+ }
+
+ private static void testMultBy10(FDBigInteger t, boolean isImmutable) throws Exception {
+ BigInteger bt = t.toBigInteger();
+ FDBigInteger r = t.multBy10();
+ if ((bt.signum() == 0 || !isImmutable) && r != t) {
+ throw new Exception("multBy10 of doesn't reuse its argument");
+ }
+ if (isImmutable) {
+ check(bt, t, "multBy10 corrupts its argument");
+ }
+ check(bt.multiply(BigInteger.TEN), r, "multBy10 returns wrong result");
+ }
+
+ private static void testMultBy10() throws Exception {
+ for (int p5 = 0; p5 <= MAX_P5; p5++) {
+ for (int p2 = 0; p2 <= MAX_P2; p2++) {
+ // This strange way of creating a value ensures that it is mutable.
+ FDBigInteger value = FDBigInteger.valueOfPow52(0, 0).multByPow52(p5, p2);
+ testMultBy10(value, false);
+ value.makeImmutable();
+ testMultBy10(value, true);
+ }
+ }
+ }
+
+ private static void testMultByPow52(FDBigInteger t, int p5, int p2) throws Exception {
+ BigInteger bt = t.toBigInteger();
+ FDBigInteger r = t.multByPow52(p5, p2);
+ if (bt.signum() == 0 && r != t) {
+ throw new Exception("multByPow52 of doesn't reuse its argument");
+ }
+ check(bt.multiply(biPow52(p5, p2)), r, "multByPow52 returns wrong result");
+ }
+
+ private static void testMultByPow52() throws Exception {
+ for (int p5 = 0; p5 <= MAX_P5; p5++) {
+ for (int p2 = 0; p2 <= MAX_P2; p2++) {
+ // This strange way of creating a value ensures that it is mutable.
+ FDBigInteger value = FDBigInteger.valueOfPow52(0, 0).multByPow52(p5, p2);
+ testMultByPow52(value, p5, p2);
+ }
+ }
+ }
+
+ private static void testLeftInplaceSub(FDBigInteger left, FDBigInteger right, boolean isImmutable) throws Exception {
+ BigInteger biLeft = left.toBigInteger();
+ BigInteger biRight = right.toBigInteger();
+ FDBigInteger diff = left.leftInplaceSub(right);
+ if (!isImmutable && diff != left) {
+ throw new Exception("leftInplaceSub of doesn't reuse its argument");
+ }
+ check(biLeft.subtract(biRight), diff, "leftInplaceSub returns wrong result");
+ }
+
+ private static void testLeftInplaceSub() throws Exception {
+ for (int p5 = 0; p5 <= MAX_P5; p5++) {
+ for (int p2 = 0; p2 <= MAX_P2; p2++) {
+// for (int p5r = 0; p5r <= p5; p5r += 10) {
+// for (int p2r = 0; p2r <= p2; p2r += 10) {
+ for (int p5r = 0; p5r <= p5; p5r++) {
+ for (int p2r = 0; p2r <= p2; p2r++) {
+ // This strange way of creating a value ensures that it is mutable.
+ FDBigInteger left = FDBigInteger.valueOfPow52(0, 0).multByPow52(p5, p2);
+ FDBigInteger right = FDBigInteger.valueOfPow52(0, 0).multByPow52(p5r, p2r);
+ testLeftInplaceSub(left, right, false);
+ left = FDBigInteger.valueOfPow52(0, 0).multByPow52(p5, p2);
+ left.makeImmutable();
+ testLeftInplaceSub(left, right, true);
+ }
+ }
+ }
+ }
+ }
+
+ private static void testRightInplaceSub(FDBigInteger left, FDBigInteger right, boolean isImmutable) throws Exception {
+ BigInteger biLeft = left.toBigInteger();
+ BigInteger biRight = right.toBigInteger();
+ FDBigInteger diff = left.rightInplaceSub(right);
+ if (!isImmutable && diff != right) {
+ throw new Exception("rightInplaceSub of doesn't reuse its argument");
+ }
+ try {
+ check(biLeft.subtract(biRight), diff, "rightInplaceSub returns wrong result");
+ } catch (Exception e) {
+ System.out.println(biLeft+" - "+biRight+" = "+biLeft.subtract(biRight));
+ throw e;
+ }
+ }
+
+ private static void testRightInplaceSub() throws Exception {
+ for (int p5 = 0; p5 <= MAX_P5; p5++) {
+ for (int p2 = 0; p2 <= MAX_P2; p2++) {
+// for (int p5r = 0; p5r <= p5; p5r += 10) {
+// for (int p2r = 0; p2r <= p2; p2r += 10) {
+ for (int p5r = 0; p5r <= p5; p5r++) {
+ for (int p2r = 0; p2r <= p2; p2r++) {
+ // This strange way of creating a value ensures that it is mutable.
+ FDBigInteger left = FDBigInteger.valueOfPow52(0, 0).multByPow52(p5, p2);
+ FDBigInteger right = FDBigInteger.valueOfPow52(0, 0).multByPow52(p5r, p2r);
+ testRightInplaceSub(left, right, false);
+ right = FDBigInteger.valueOfPow52(0, 0).multByPow52(p5r, p2r);
+ right.makeImmutable();
+ testRightInplaceSub(left, right, true);
+ }
+ }
+ }
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ testValueOfPow52();
+ testValueOfMulPow52();
+ testLeftShift();
+ testQuoRemIteration();
+ testCmp();
+ testCmpPow52();
+ testAddAndCmp();
+ // Uncomment the following for more comprehensize but slow testing.
+ // testLeftInplaceSub();
+ // testMultBy10();
+ // testMultByPow52();
+ // testRightInplaceSub();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/misc/FloatingDecimal/TestFloatingDecimal.java Wed Jun 05 21:01:02 2013 -0700
@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.util.Random;
+import sun.misc.FloatingDecimal;
+
+/*
+OldFloatingDecimalForTest
+
+public class OldFloatingDecimalForTest {
+ public boolean digitsRoundedUp();
+ public OldFloatingDecimalForTest(double);
+ public OldFloatingDecimalForTest(float);
+ public boolean decimalDigitsExact();
+ public java.lang.String toString();
+ public java.lang.String toJavaFormatString();
+ public void appendTo(java.lang.Appendable);
+ public static OldFloatingDecimalForTest readJavaFormatString(java.lang.String) throws java.lang.NumberFormatException;
+ public strictfp double doubleValue();
+ public strictfp float floatValue();
+}
+
+sun.misc.FloatingDecimal
+
+public class sun.misc.FloatingDecimal {
+ public sun.misc.FloatingDecimal();
+ public static java.lang.String toJavaFormatString(double);
+ public static java.lang.String toJavaFormatString(float);
+ public static void appendTo(double, java.lang.Appendable);
+ public static void appendTo(float, java.lang.Appendable);
+ public static double parseDouble(java.lang.String) throws java.lang.NumberFormatException;
+ public static float parseFloat(java.lang.String) throws java.lang.NumberFormatException;
+ public static sun.misc.FloatingDecimal$AbstractD2ABuffer getD2ABuffer(double);
+}
+*/
+
+/**
+ * @test
+ * @bug 7032154
+ * @summary unit tests of sun.misc.FloatingDecimal
+ * @author Brian Burkhalter
+ */
+public class TestFloatingDecimal {
+ private static enum ResultType {
+ RESULT_EXCEPTION,
+ RESULT_PRINT
+ }
+
+ private static final ResultType RESULT_TYPE = ResultType.RESULT_PRINT;
+ private static final int NUM_RANDOM_TESTS = 100000;
+
+ private static final Random RANDOM = new Random();
+
+ private static void result(String message) {
+ switch (RESULT_TYPE) {
+ case RESULT_EXCEPTION:
+ throw new RuntimeException(message);
+ case RESULT_PRINT:
+ System.err.println(message);
+ break;
+ default:
+ assert false;
+ }
+ }
+
+ private static int check(String test, Object expected, Object actual) {
+ int failures = 0;
+ if(!actual.equals(expected)) {
+ failures++;
+ result("Test "+test+" expected "+expected+" but obtained "+actual);
+ }
+ return failures;
+ }
+
+ private static int testAppendToDouble() {
+ System.out.println(" testAppendToDouble");
+ int failures = 0;
+
+ for(int i = 0; i < NUM_RANDOM_TESTS; i++) {
+ double[] d = new double[] {
+ RANDOM.nextLong(),
+ RANDOM.nextGaussian(),
+ RANDOM.nextDouble()*Double.MAX_VALUE
+ };
+ for(int j = 0; j < d.length; j++) {
+ OldFloatingDecimalForTest ofd = new OldFloatingDecimalForTest(d[j]);
+ StringBuilder sb = new StringBuilder();
+ ofd.appendTo(sb);
+ String oldString = sb.toString();
+ sb = new StringBuilder();
+ FloatingDecimal.appendTo(d[j], sb);
+ String newString = sb.toString();
+ failures += check("testAppendToDouble", oldString, newString);
+ }
+ }
+
+ return failures;
+ }
+
+ private static int testAppendToFloat() {
+ System.out.println(" testAppendToFloat");
+ int failures = 0;
+
+ for(int i = 0; i < NUM_RANDOM_TESTS; i++) {
+ float[] f = new float[] {
+ RANDOM.nextLong(),
+ (float)RANDOM.nextGaussian(),
+ RANDOM.nextFloat()*Float.MAX_VALUE
+ };
+ for(int j = 0; j < f.length; j++) {
+ OldFloatingDecimalForTest ofd = new OldFloatingDecimalForTest(f[j]);
+ StringBuilder sb = new StringBuilder();
+ ofd.appendTo(sb);
+ String oldString = sb.toString();
+ sb = new StringBuilder();
+ FloatingDecimal.appendTo(f[j], sb);
+ String newString = sb.toString();
+ failures += check("testAppendToFloat", oldString, newString);
+ }
+ }
+
+ return failures;
+ }
+
+ private static int testAppendTo() {
+ System.out.println("testAppendTo");
+ int failures = 0;
+
+ failures += testAppendToDouble();
+ failures += testAppendToFloat();
+
+ return failures;
+ }
+
+ private static int testParseDouble() {
+ System.out.println(" testParseDouble");
+ int failures = 0;
+
+ for(int i = 0; i < NUM_RANDOM_TESTS; i++) {
+ double[] d = new double[] {
+ RANDOM.nextLong(),
+ RANDOM.nextGaussian(),
+ RANDOM.nextDouble()*Double.MAX_VALUE
+ };
+ for(int j = 0; j < d.length; j++) {
+ OldFloatingDecimalForTest ofd = new OldFloatingDecimalForTest(d[j]);
+ String javaFormatString = ofd.toJavaFormatString();
+ ofd = OldFloatingDecimalForTest.readJavaFormatString(javaFormatString);
+ double oldDouble = ofd.doubleValue();
+ double newDouble = FloatingDecimal.parseDouble(javaFormatString);
+ failures += check("testParseDouble", oldDouble, newDouble);
+ }
+ }
+
+ return failures;
+ }
+
+ private static int testParseFloat() {
+ System.out.println(" testParseFloat");
+ int failures = 0;
+
+ for(int i = 0; i < NUM_RANDOM_TESTS; i++) {
+ float[] f = new float[] {
+ RANDOM.nextInt(),
+ (float)RANDOM.nextGaussian(),
+ RANDOM.nextFloat()*Float.MAX_VALUE
+ };
+ for(int j = 0; j < f.length; j++) {
+ OldFloatingDecimalForTest ofd = new OldFloatingDecimalForTest(f[j]);
+ String javaFormatString = ofd.toJavaFormatString();
+ ofd = OldFloatingDecimalForTest.readJavaFormatString(javaFormatString);
+ float oldFloat = ofd.floatValue();
+ float newFloat = FloatingDecimal.parseFloat(javaFormatString);
+ failures += check("testParseFloat", oldFloat, newFloat);
+ }
+ }
+
+ return failures;
+ }
+
+ private static int testParse() {
+ System.out.println("testParse");
+ int failures = 0;
+
+ failures += testParseDouble();
+ failures += testParseFloat();
+
+ return failures;
+ }
+
+ private static int testToJavaFormatStringDoubleFixed() {
+ System.out.println(" testToJavaFormatStringDoubleFixed");
+ int failures = 0;
+
+ double[] d = new double [] {
+ -5.9522650387500933e18, // dtoa() fast path
+ 0.872989018674569, // dtoa() fast iterative - long
+ 1.1317400099603851e308 // dtoa() slow iterative
+ };
+
+ for(int i = 0; i < d.length; i++) {
+ OldFloatingDecimalForTest ofd = new OldFloatingDecimalForTest(d[i]);
+ failures += check("testToJavaFormatStringDoubleFixed", ofd.toJavaFormatString(), FloatingDecimal.toJavaFormatString(d[i]));
+ }
+
+ return failures;
+ }
+
+ private static int testToJavaFormatStringDoubleRandom() {
+ System.out.println(" testToJavaFormatStringDoubleRandom");
+ int failures = 0;
+
+ for(int i = 0; i < NUM_RANDOM_TESTS; i++) {
+ double[] d = new double[] {
+ RANDOM.nextLong(),
+ RANDOM.nextGaussian(),
+ RANDOM.nextDouble()*Double.MAX_VALUE
+ };
+ for(int j = 0; j < d.length; j++) {
+ OldFloatingDecimalForTest ofd = new OldFloatingDecimalForTest(d[j]);
+ failures += check("testToJavaFormatStringDoubleRandom", ofd.toJavaFormatString(), FloatingDecimal.toJavaFormatString(d[j]));
+ }
+ }
+
+ return failures;
+ }
+
+ private static int testToJavaFormatStringDouble() {
+ System.out.println(" testToJavaFormatStringDouble");
+ int failures = 0;
+ failures += testToJavaFormatStringDoubleFixed();
+ failures += testToJavaFormatStringDoubleRandom();
+ return failures;
+ }
+
+ private static int testToJavaFormatStringFloatFixed() {
+ System.out.println(" testToJavaFormatStringFloatFixed");
+ int failures = 0;
+
+ float[] f = new float[] {
+ -9.8784166e8f, // dtoa() fast path
+ 0.70443946f, // dtoa() fast iterative - int
+ 1.8254228e37f // dtoa() slow iterative
+ };
+
+ for(int i = 0; i < f.length; i++) {
+ OldFloatingDecimalForTest ofd = new OldFloatingDecimalForTest(f[i]);
+ failures += check("testToJavaFormatStringFloatFixed", ofd.toJavaFormatString(), FloatingDecimal.toJavaFormatString(f[i]));
+ }
+
+ return failures;
+ }
+
+ private static int testToJavaFormatStringFloatRandom() {
+ System.out.println(" testToJavaFormatStringFloatRandom");
+ int failures = 0;
+
+ for(int i = 0; i < NUM_RANDOM_TESTS; i++) {
+ float[] f = new float[] {
+ RANDOM.nextInt(),
+ (float)RANDOM.nextGaussian(),
+ RANDOM.nextFloat()*Float.MAX_VALUE
+ };
+ for(int j = 0; j < f.length; j++) {
+ OldFloatingDecimalForTest ofd = new OldFloatingDecimalForTest(f[j]);
+ failures += check("testToJavaFormatStringFloatRandom", ofd.toJavaFormatString(), FloatingDecimal.toJavaFormatString(f[j]));
+ }
+ }
+
+ return failures;
+ }
+
+ private static int testToJavaFormatStringFloat() {
+ System.out.println(" testToJavaFormatStringFloat");
+ int failures = 0;
+
+ failures += testToJavaFormatStringFloatFixed();
+ failures += testToJavaFormatStringFloatRandom();
+
+ return failures;
+ }
+
+ private static int testToJavaFormatString() {
+ System.out.println("testToJavaFormatString");
+ int failures = 0;
+
+ failures += testToJavaFormatStringDouble();
+ failures += testToJavaFormatStringFloat();
+
+ return failures;
+ }
+
+ public static void main(String[] args) {
+ int failures = 0;
+
+ failures += testAppendTo();
+ failures += testParse();
+ failures += testToJavaFormatString();
+
+ if (failures != 0) {
+ throw new RuntimeException("" + failures + " failures while testing FloatingDecimal");
+ }
+ }
+}