src/share/classes/sun/misc/FloatingDecimal.java

Print this page

        

@@ -23,281 +23,333 @@
  * questions.
  */
 
 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;
 
-    /*
-     * 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.
-     */
+    static final int    INT_DECIMAL_DIGITS = 9;
 
-    // True if the dtoa() binary to decimal conversion was exact.
-    boolean     exactDecimalConversion = false;
+    /**
+     * 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();
+    }
 
-    // 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;
+    /**
+     * 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();
+    }
 
-    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;
+    /**
+     * 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);
     }
 
-    /*
-     * 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 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 ) );
+    /**
+     * 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);
             }
+
+    /**
+     * 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();
     }
 
-    //
-    // 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;
-    }
-
-    /*
-     * 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.
+    /**
+     * A converter which can process single or double precision floating point
+     * values into an ASCII <code>String</code> representation.
+     */
+    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);
+
+        /**
+         * 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();
+
+        /**
+         * 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();
+
+        /**
+         * Indicates whether the value was rounded up during the binary to ASCII
+         * conversion.
      *
-     * AS A SIDE EFFECT, THIS METHOD WILL SET THE INSTANCE VARIABLES
-     * bigIntExp and bigIntNBits
+         * @return <code>true</code> if and only if the value was rounded up.
+         */
+        public boolean digitsRoundedUp();
+
+        /**
+         * Indicates whether the binary to ASCII conversion was exact.
      *
+         * @return <code>true</code> if any only if the conversion was exact.
      */
-    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;
+        public boolean decimalDigitsExact();
+    }
+
+    /**
+     * A <code>BinaryToASCIIConverter</code> which represents <code>NaN</code>
+     * and infinite values.
+     */
+    private static class ExceptionalBinaryToASCIIBuffer implements BinaryToASCIIConverter {
+        final private String image;
+        private boolean isNegative;
+
+        public ExceptionalBinaryToASCIIBuffer(String image, boolean isNegative) {
+            this.image = image;
+            this.isNegative = isNegative;
+        }
+
+        @Override
+        public String toJavaFormatString() {
+            return image;
+        }
+
+        @Override
+        public void appendTo(Appendable buf) {
+            if (buf instanceof StringBuilder) {
+                ((StringBuilder) buf).append(image);
+            } else if (buf instanceof StringBuffer) {
+                ((StringBuffer) buf).append(image);
+            } else {
+                assert false;
             }
         }
-        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 );
+
+        @Override
+        public int getDecimalExponent() {
+            throw new IllegalArgumentException("Exceptional value does not have an exponent");
     }
 
-    /*
-     * 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.
+        @Override
+        public int getDigits(char[] digits) {
+            throw new IllegalArgumentException("Exceptional value does not have digits");
+        }
+
+        @Override
+        public boolean isNegative() {
+            return isNegative;
+        }
+
+        @Override
+        public boolean isExceptional() {
+            return true;
+        }
+
+        @Override
+        public boolean digitsRoundedUp() {
+            throw new IllegalArgumentException("Exceptional value is not rounded");
+        }
+
+        @Override
+        public boolean decimalDigitsExact() {
+            throw new IllegalArgumentException("Exceptional value is not exact");
+        }
+    }
+
+    private static final String INFINITY_REP = "Infinity";
+    private static final int INFINITY_LENGTH = INFINITY_REP.length();
+    private static final String NAN_REP = "NaN";
+    private static final int NAN_LENGTH = NAN_REP.length();
+
+    private static final BinaryToASCIIConverter B2AC_POSITIVE_INFINITY = new ExceptionalBinaryToASCIIBuffer(INFINITY_REP, false);
+    private static final BinaryToASCIIConverter B2AC_NEGATIVE_INFINITY = new ExceptionalBinaryToASCIIBuffer("-" + INFINITY_REP, true);
+    private static final BinaryToASCIIConverter B2AC_NOT_A_NUMBER = new ExceptionalBinaryToASCIIBuffer(NAN_REP, false);
+    private static final BinaryToASCIIConverter B2AC_POSITIVE_ZERO = new BinaryToASCIIBuffer(false, new char[]{'0'});
+    private static final BinaryToASCIIConverter B2AC_NEGATIVE_ZERO = new BinaryToASCIIBuffer(true,  new char[]{'0'});
+
+    /**
+     * A buffered implementation of <code>BinaryToASCIIConverter</code>.
      */
-    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;
+    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];
         }
-        if ( binexp > expShift ){
-            ulpval = Double.longBitsToDouble( ((long)(binexp-expShift))<<expShift );
-        } else if ( binexp == 0 ){
-            ulpval = Double.MIN_VALUE;
+
+        /**
+         * 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;
+        }
+
+        @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 {
-            ulpval = Double.longBitsToDouble( 1L<<(binexp-1) );
+                assert false;
+            }
         }
-        if ( subtracting ) ulpval = - ulpval;
 
-        return ulpval;
+        @Override
+        public int getDecimalExponent() {
+            return decExponent;
     }
 
-    /*
-     * 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;
+        @Override
+        public int getDigits(char[] digits) {
+            System.arraycopy(this.digits,firstDigitIndex,digits,0,this.nDigits);
+            return this.nDigits;
         }
-        lbits += (long)roundDir; // hack-o-matic.
-        return (float)Double.longBitsToDouble( lbits );
+
+        @Override
+        public boolean isNegative() {
+            return isNegative;
+        }
+
+        @Override
+        public boolean isExceptional() {
+            return false;
+        }
+
+        @Override
+        public boolean digitsRoundedUp() {
+            return decimalDigitsRoundedUp;
+        }
+
+        @Override
+        public boolean decimalDigitsExact() {
+            return exactDecimalConversion;
     }
 
+        private void setSign(boolean isNegative) {
+            this.isNegative = isNegative;
+        }
 
-    /*
+        /**
      * 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.

@@ -308,40 +360,30 @@
      * 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;
-        //
+        private void developLongDigits( int decExponent, long lvalue, int insignificantDigits ){
+            if ( insignificantDigits != 0 ){
         // 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 pow10 = FDBigInteger.LONG_5_POW[insignificantDigits] << insignificantDigits; // 10^i == 5^i * 2^i;
             long residue = lvalue % pow10;
             lvalue /= pow10;
-            decExponent += i;
+                decExponent += insignificantDigits;
             if ( residue >= (pow10>>1) ){
                 // round up based on the low-order bits we're discarding
                 lvalue++;
             }
         }
+            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;
-            ndigits = 10;
-            digits = perThreadBuffer.get();
-            digitno = ndigits-1;
             c = ivalue%10;
             ivalue /= 10;
             while ( c == 0 ){
                 decExponent++;
                 c = ivalue%10;

@@ -355,13 +397,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);

@@ -373,362 +412,198 @@
                 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 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;
-        }
-        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;
-
-        // 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 );
+            this.firstDigitIndex = digitno;
+            this.nDigits = this.digits.length - digitno;
     }
 
-    private void
-    dtoa( int binExp, long fractBits, int nSignificantBits )
+        private void dtoa( int binExp, long fractBits, int nSignificantBits, boolean isCompatibleFormat)
     {
-        int     nFractBits; // number of significant bits of fractBits;
-        int     nTinyBits;  // number of these to the right of the point.
-        int     decExp;
-
+            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.
-        nFractBits = countBits( fractBits );
-        nTinyBits = Math.max( 0, nFractBits - binExp - 1 );
-        if ( binExp <= maxSmallBinExp && binExp >= minSmallBinExp ){
+            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;
+
+            // 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 < 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 < 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 ){
-                        halfULP = 1L << ( binExp-nSignificantBits-1);
+                            insignificant = insignificantDigitsForPow2(binExp-nSignificantBits-1);
                     } else {
-                        halfULP = 0L;
+                            insignificant = 0;
                     }
-                    if ( binExp >= expShift ){
-                        fractBits <<= (binExp-expShift);
+                        if ( binExp >= EXP_SHIFT ){
+                            fractBits <<= (binExp-EXP_SHIFT);
                     } else {
-                        fractBits >>>= (expShift-binExp) ;
+                            fractBits >>>= (EXP_SHIFT-binExp) ;
                     }
-                    developLongDigits( 0, fractBits, halfULP );
+                        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 >>>= expShift+1-nFractBits;
-                 *     fractBits *= long5pow[ nTinyBits ];
-                 *     halfULP = long5pow[ nTinyBits ] >> (1+nSignificantBits-nFractBits);
-                 *     developLongDigits( -nTinyBits, 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 >>>= EXP_SHIFT+1-nFractBits;
+                    //     fractBits//= long5pow[ nTinyBits ];
+                    //     halfULP = long5pow[ nTinyBits ] >> (1+nSignificantBits-nFractBits);
+                    //     developLongDigits( -nTinyBits, fractBits, insignificantDigits(halfULP) );
+                    //     return;
+                    // }
+                    //
             }
         }
-        /*
-         * This is the hard case. We are going to compute large positive
-         * integers B and S and integer decExp, s.t.
-         *      d = ( B / S ) * 10^decExp
-         *      1 <= B / S < 10
-         * Obvious choices are:
-         *      decExp = floor( log10(d) )
-         *      B      = d * 2^nTinyBits * 10^max( 0, -decExp )
-         *      S      = 10^max( 0, decExp) * 2^nTinyBits
-         * (noting that nTinyBits has already been forced to non-negative)
-         * I am also going to compute a large positive integer
-         *      M      = (1/2^nSignificantBits) * 2^nTinyBits * 10^max( 0, -decExp )
-         * i.e. M is (1/2) of the ULP of d, scaled like B.
-         * When we iterate through dividing B/S and picking off the
-         * quotient bits, we will know when to stop when the remainder
-         * is <= M.
-         *
-         * We keep track of powers of 2 and powers of 5.
-         */
-
-        /*
-         * 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;
+            //
+            // 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 (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);
+            //
+            // 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 )
+            //
+            // 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];
+            //
+            // Construct, Scale, iterate.
+            // Some day, we'll write a stopping test that takes
+            // account of the asymmetry of the spacing of floating-point
+            // numbers below perfect powers of 2
+            // 26 Sept 96 is not that day.
+            // So we use a symmetric test.
+            //
         int  ndigit = 0;
         boolean low, high;
         long lowDigitDifference;
         int  q;
 
-        /*
-         * Detect the special cases where all the numbers we are about
-         * to compute will fit in int or long integers.
-         * In these cases, we will avoid doing 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 ));
+            //
+            // 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 ));
+
+            // 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 * small5pow[B5] ) << B2;
-                int s = small5pow[S5] << S2;
-                int m = small5pow[M5] << M2;
+                    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.
-                 */
+                    //
+                    // 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 );

@@ -738,17 +613,17 @@
                     // 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 ){
+                    //
+                    // 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 );

@@ -770,19 +645,19 @@
                 }
                 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 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.
-                 */
+                    //
+                    // 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 );

@@ -792,17 +667,17 @@
                     // 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 ){
+                    //
+                    // 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 );

@@ -824,736 +699,686 @@
                 }
                 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.
-             */
+                //
+                // 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 );
-            Mval = Mval.mult( 10 );
             low  = (Bval.cmp( Mval ) < 0);
-            high = (Bval.add( Mval ).cmp( tenSval ) > 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 ( decExp < -3 || decExp >= 8 ){
+                //
+                // 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 );
-                Mval = Mval.mult( 10 );
                 assert q < 10 : q;  // excessively large digit
+                    Mval = Mval.multBy10(); //Mval = Mval.mult( 10 );
                 low  = (Bval.cmp( Mval ) < 0);
-                high = (Bval.add( Mval ).cmp( tenSval ) > 0 );
+                    high = tenSval.addAndCmp(Bval,Mval)<=0;
                 digits[ndigit++] = (char)('0' + q);
             }
             if ( high && low ){
-                Bval.lshiftMe(1);
+                    Bval = Bval.leftShift(1);
                 lowDigitDifference = Bval.cmp(tenSval);
             } else {
                 lowDigitDifference = 0L; // this here only for flow analysis!
             }
-            exactDecimalConversion  = (Bval.cmp( ZeroVal ) == 0);
+                exactDecimalConversion  = (Bval.cmp( FDBigInteger.ZERO ) == 0);
         }
         this.decExponent = decExp+1;
-        this.digits = digits;
+            this.firstDigitIndex = 0;
         this.nDigits = ndigit;
-        /*
-         * Last digit gets rounded based on stopping condition.
-         */
+            //
+            // 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();
+                        if ( (digits[firstDigitIndex+nDigits-1]&1) != 0 ) {
+                            roundup();
+                        }
                 } else if ( lowDigitDifference > 0 ){
                     roundup();
                 }
             } else {
                 roundup();
             }
         }
     }
 
-    public boolean decimalDigitsExact() {
-        return exactDecimalConversion;
+        // 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;
+                }
+                // else fall through.
+            }
+            digits[i] = (char) (q + 1);
+            decimalDigitsRoundedUp = true;
+        }
+
+        /**
+         * 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.
+         */
+        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;
+            }
     }
 
-    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 );
+        private static int insignificantDigits(int insignificant) {
+            int i;
+            for ( i = 0; insignificant >= 10L; i++ ) {
+                insignificant /= 10L;
         }
-        return new String(result);
+            return i;
     }
 
-    public String toJavaFormatString() {
-        char result[] = perThreadBuffer.get();
-        int i = getChars(result);
-        return new String(result, 0, i);
+        /**
+         * 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
+        };
+
+        // 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,
+        };
+
     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 (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';
                 } else {
                     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';
                 }
                 result[i++] = 'E';
                 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;
     }
 
-    // Per-thread buffer for string/stringbuffer conversion
-    private static ThreadLocal<char[]> perThreadBuffer = new ThreadLocal<char[]>() {
-            protected synchronized char[] initialValue() {
-                return new char[26];
+    }
+
+    private static final ThreadLocal<BinaryToASCIIBuffer> threadLocalBinaryToASCIIBuffer =
+            new ThreadLocal<BinaryToASCIIBuffer>() {
+                @Override
+                protected BinaryToASCIIBuffer initialValue() {
+                    return new BinaryToASCIIBuffer();
             }
         };
 
-    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 BinaryToASCIIBuffer getBinaryToASCIIBuffer() {
+        return threadLocalBinaryToASCIIBuffer.get();
     }
 
-    @SuppressWarnings("fallthrough")
-    public static FloatingDecimal
-    readJavaFormatString( String in ) throws NumberFormatException {
-        boolean isNegative = false;
-        boolean signSeen   = false;
-        int     decExp;
-        char    c;
+    /**
+     * 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();
 
-    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"
+    /**
+     * A <code>ASCIIToBinaryConverter</code> container for a <code>double</code>.
+     */
+    static class PreparedASCIIToBinaryBuffer implements ASCIIToBinaryConverter {
+        final private double doubleVal;
+        private int roundDir = 0;
 
-                if(c == 'N') {
-                    targetChars = notANumber;
-                    potentialNaN = true;
-                } else {
-                    targetChars = infinity;
+        public PreparedASCIIToBinaryBuffer(double doubleVal) {
+            this.doubleVal = doubleVal;
                 }
 
-                // compare Input string to "NaN" or "Infinity"
-                int j = 0;
-                while(i < l && j < targetChars.length) {
-                    if(in.charAt(i) == targetChars[j]) {
-                        i++; j++;
+        public PreparedASCIIToBinaryBuffer(double doubleVal, int roundDir) {
+            this.doubleVal = doubleVal;
+            this.roundDir = roundDir;
                     }
-                    else // something is amiss, throw exception
-                        break parseNumber;
+
+        @Override
+        public double doubleValue() {
+            return doubleVal;
                 }
 
-                // 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)) ;
+        @Override
+        public float floatValue() {
+            return stickyRound(doubleVal,roundDir);
                 }
-                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
+    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);
 
-            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");
+    /**
+     * 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;
                     }
-                    decPt = i;
-                    if ( signSeen ){
-                        decPt -= 1;
+
+        @Override
+        public double doubleValue() {
+            return doubleValue(false);
                     }
-                    decSeen = true;
-                    break; // out of switch.
-                default:
-                    break digitLoop;
+
+        /**
+         * 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;
                 }
-                i++;
+            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));
             }
-            /*
-             * 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
+            if (subtracting) {
+                ulpval = -ulpval;
                 }
 
+            return ulpval;
             }
 
-            /* 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.
+        /**
+         * 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.
              */
-            if ( decSeen ){
-                decExp = decPt - nLeadZero;
-            } else {
-                decExp = nDigits+nTrailZero;
-            }
+        private strictfp double doubleValue(boolean mustSetRoundDir) {
+            int kDigits = Math.min(nDigits, MAX_DECIMAL_DIGITS + 1);
+            long lValue;
+            double dValue;
+            double rValue;
 
-            /*
-             * 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;
+            if (mustSetRoundDir) {
+                roundDir = 0;
                     }
-                    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.
+            //
+            // 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
                 }
-                int expLimit = bigDecimalExponent+nDigits+nTrailZero;
-                if ( expOverflow || ( expVal > expLimit ) ){
+                else if (exp >= 0) {
+                    if (exp <= MAX_SMALL_TEN) {
                     //
-                    // 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. )
+                        // Can get the answer with one operation,
+                        // thus one roundoff.
                     //
-                    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 FloatingDecimal( 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 {
+                        rValue = dValue * SMALL_10_POW[exp];
             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
+                            double tValue = rValue / SMALL_10_POW[exp];
+                            roundDir = (tValue == dValue) ? 0
+                                    : (tValue < dValue) ? 1
                                 : -1;
                         }
-                        return (isNegative)? -rValue : rValue;
+                        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
+                    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;
+                        return (isNegative) ? -rValue : rValue;
                     }
-                    /*
-                     * Else we have a hard case with a positive exp.
-                     */
+                    //
+                    // 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
+                    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;
+                        return (isNegative) ? -rValue : rValue;
                     }
-                    /*
-                     * Else we have a hard case with a negative exp.
-                     */
+                    //
+                    // 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;
+            //
+            // 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 *= small10pow[exp&15];
+                if ((exp & 15) != 0) {
+                    dValue *= SMALL_10_POW[exp & 15];
                 }
-                if ( (exp>>=4) != 0 ){
+                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 ).
-                         */
+                    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 *= big10pow[j];
-                        if ( Double.isInfinite( t ) ){
-                            return (isNegative)? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
+                        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 ){
+            } 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 (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 /= small10pow[exp&15];
+                if ((exp & 15) != 0) {
+                    dValue /= SMALL_10_POW[exp & 15];
                 }
-                if ( (exp>>=4) != 0 ){
+                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 ).
-                         */
+                    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 *= tiny10pow[j];
-                        if ( t == 0.0 ){
-                            return (isNegative)? -0.0 : 0.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 FDBigInt arithmetic.
-             * Formulate the EXACT big-number result as
-             * bigD0 * 10^exp
-             */
-            FDBigInt bigD0 = new FDBigInt( lValue, digits, kDigits, nDigits );
+            //
+            // 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){
-                /* 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
+            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 ( exp >= 0 ){
-                    B2 = B5 = 0;
-                    D2 = D5 = exp;
-                } else {
-                    B2 = B5 = -exp;
-                    D2 = D5 = 0;
-                }
-                if ( bigIntExp >= 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 ){
+                if (binexp <= -DoubleConsts.EXP_BIAS) {
                     // 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;
+                    // half an ULP is at 2^-(expBias+EXP_SHIFT+1)
+                    hulpbias = binexp + lowOrderZeros + DoubleConsts.EXP_BIAS;
                 } else {
-                    hulpbias = expShift + 2 - bigIntNBits;
+                    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 ) );
+                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 );
+                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

@@ -1564,446 +1389,689 @@
                 // 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;
+                FDBigInteger diff;
                 int cmpResult;
                 boolean overvalue;
-                if ( (cmpResult = bigB.cmp( bigD ) ) > 0 ){
+                if ((cmpResult = bigB.cmp(bigD)) > 0) {
                     overvalue = true; // our candidate is too big.
-                    diff = bigB.sub( bigD );
-                    if ( (bigIntNBits == 1) && (bigIntExp > -expBias+1) ){
+                    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. We will be subtracting.
+                        // 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 ){
+                        if (Ulp2 < 0) {
                             // rats. Cannot de-scale ulp this far.
                             // must scale diff in other direction.
                             Ulp2 = 0;
-                            diff.lshiftMe( 1 );
+                            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
+        };
+
+        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")
+    static ASCIIToBinaryConverter 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 len = in.length();
+            if ( len == 0 ) {
+                throw new NumberFormatException("empty String");
+            }
+            int i = 0;
+            switch (in.charAt(i)){
+            case '-':
+                isNegative = true;
+                //FALLTHROUGH
+            case '+':
+                i++;
+                signSeen = true;
+            }
+            c = in.charAt(i);
+            if(c == 'N') { // Check for NaN
+                if((len-i)==NAN_LENGTH && in.indexOf(NAN_REP,i)==i) {
+                    return A2BC_NOT_A_NUMBER;
+                }
+                // 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);
+                    }
+                }
+            }  // look for and process decimal floating-point string
+
+            char[] digits = new char[ len ];
+            int    nDigits= 0;
+            boolean decSeen = false;
+            int decPt = 0;
+            int nLeadZero = 0;
+            int nTrailZero= 0;
+
+        skipLeadingZerosLoop:
+            while (i < len) {
+                c = in.charAt(i);
+                if (c == '0') {
+                    nLeadZero++;
+                } else if (c == '.') {
+                    if (decSeen) {
+                        // already saw one ., this is the 2nd.
+                        throw new NumberFormatException("multiple points");
+                    }
+                    decPt = i;
+                    if (signSeen) {
+                        decPt -= 1;
+                    }
+                    decSeen = true;
+                } else {
+                    break skipLeadingZerosLoop;
+                }
+                i++;
+            }
+        digitLoop:
+            while (i < len) {
+                c = in.charAt(i);
+                if (c >= '1' && c <= '9') {
+                    digits[nDigits++] = c;
+                    nTrailZero = 0;
+                } else if (c == '0') {
+                    digits[nDigits++] = c;
+                    nTrailZero++;
+                } else if (c == '.') {
+                    if (decSeen) {
+                        // already saw one ., this is the 2nd.
+                        throw new NumberFormatException("multiple points");
+                    }
+                    decPt = i;
+                    if (signSeen) {
+                        decPt -= 1;
+                    }
+                    decSeen = true;
+                } else {
+                    break digitLoop;
+                }
+                i++;
+            }
+            nDigits -=nTrailZero;
+            //
+            // At this point, we've scanned all the digits and decimal
+            // point we're going to see. Trim off leading and trailing
+            // zeros, which will just confuse us later, and adjust
+            // our initial decimal exponent accordingly.
+            // To review:
+            // we have seen i total characters.
+            // nLeadZero of them were zeros before any other digits.
+            // nTrailZero of them were zeros after any other digits.
+            // if ( decSeen ), then a . was seen after decPt characters
+            // ( including leading zeros which have been discarded )
+            // nDigits characters were neither lead nor trailing
+            // zeros, nor point
+            //
+            //
+            // special hack: if we saw no non-zero digits, then the
+            // answer is zero!
+            // Unfortunately, we feel honor-bound to keep parsing!
+            //
+            boolean isZero = (nDigits == 0);
+            if ( isZero &&  nLeadZero == 0 ){
+                // we saw NO DIGITS AT ALL,
+                // not even a crummy 0!
+                // this is not allowed.
+                break parseNumber; // 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 < len) &&  (((c = in.charAt(i) )=='e') || (c == 'E') ) ){
+                int expSign = 1;
+                int expVal  = 0;
+                int reallyBig = Integer.MAX_VALUE / 10;
+                boolean expOverflow = false;
+                switch( in.charAt(++i) ){
+                case '-':
+                    expSign = -1;
+                    //FALLTHROUGH
+                case '+':
+                    i++;
                     }
-                } 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;
+                int expAt = i;
+            expLoop:
+                while ( i < len  ){
+                    if ( expVal >= reallyBig ){
+                        // the next character will cause integer
+                        // overflow.
+                        expOverflow = true;
                 }
-                FDBigInt halfUlp = constructPow52( B5, Ulp2 );
-                if ( (cmpResult = diff.cmp( halfUlp ) ) < 0 ){
-                    // difference is small.
-                    // this is close enough
-                    if (mustSetRoundDir) {
-                        roundDir = overvalue ? -1 : 1;
+                    c = in.charAt(i++);
+                    if(c>='0' && c<='9') {
+                        expVal = expVal*10 + ( (int)c - (int)'0' );
+                    } else {
+                        i--;           // back up.
+                        break expLoop; // stop parsing exponent.
                     }
-                    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;
+                int expLimit = BIG_DECIMAL_EXPONENT+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 {
-                    // 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.
+                    // 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
             }
-            return (isNegative)? -dValue : dValue;
         }
+            //
+            // 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
     }
-
-    /*
-     * 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 );
+            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 + "\"");
     }
 
-
-    /*
-     * All the positive powers of 10 that can be
-     * represented exactly in double/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.
      */
-    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' };
+    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;
+            }
+            lbits += (long)roundDirection; // hack-o-matic.
+            return (float)Double.longBitsToDouble( lbits );
+        } else {
+            return (float)dval;
+        }
+    }
 
 
-    /*
+    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 Pattern hexFloatPattern = null;
-    private static synchronized Pattern getHexFloatPattern() {
-        if (hexFloatPattern == null) {
-           hexFloatPattern = Pattern.compile(
+        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) {
+   static ASCIIToBinaryConverter parseHexString(String s) {
         // Verify string is a member of the hexadecimal floating-point
         // string language.
-        Matcher m = getHexFloatPattern().matcher(s);
+            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.
-             *
-             * 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.
-             */
-
+                //
+                // 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;
-
+                boolean isNegative = ((group1 != null) && group1.equals("-"));
 
             //  Extract Significand magnitude
-            /*
-             * Based on the form of the significand, calculate how the
-             * binary exponent needs to be adjusted to create a
-             * normalized *hexadecimal* floating-point number; that
-             * is, a number where there is one nonzero hex digit to
-             * the left of the (hexa)decimal point.  Since we are
-             * adjusting a binary, not hexadecimal exponent, the
-             * exponent is adjusted by a multiple of 4.
-             *
-             * There are a number of significand scenarios to consider;
-             * letters are used in indicate nonzero digits:
-             *
-             * 1. 000xxxx       =>      x.xxx   normalized
-             *    increase exponent by (number of x's - 1)*4
-             *
-             * 2. 000xxx.yyyy =>        x.xxyyyy        normalized
-             *    increase exponent by (number of x's - 1)*4
-             *
-             * 3. .000yyy  =>   y.yy    normalized
-             *    decrease exponent by (number of zeros + 1)*4
-             *
-             * 4. 000.00000yyy => y.yy normalized
-             *    decrease exponent by (number of zeros to right of point + 1)*4
-             *
-             * If the significand is exactly zero, return a properly
-             * signed zero.
-             */
+                //
+                // 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;
+                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.
-                 */
+                    //
+                    // 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
+                    if ((group4 = m.group(4)) != null) {  // Integer-only significand
                     // Leading zeros never matter on the integer portion
                     significandString = stripLeadingZeros(group4);
                     leftDigits = significandString.length();
-                }
-                else {
+                    } else {
                     // Group 6 is the optional integer; leading zeros
                     // never matter on the integer portion
                     String group6 = stripLeadingZeros(m.group(6));
                     leftDigits = group6.length();
 

@@ -2011,45 +2079,45 @@
                     String group7 = m.group(7);
                     rightDigits = group7.length();
 
                     // Turn "integer.fraction" into "integer"+"fraction"
                     significandString =
-                        ((group6 == null)?"":group6) + // is the null
+                                ((group6 == null) ? "" : group6) + // is the null
                         // check necessary?
                         group7;
                 }
 
                 significandString = stripLeadingZeros(significandString);
                 signifLength  = significandString.length();
 
-                /*
-                 * Adjust exponent as described above
-                 */
+                    //
+                    // Adjust exponent as described above
+                    //
                 if (leftDigits >= 1) {  // Cases 1 and 2
-                    exponentAdjust = 4*(leftDigits - 1);
+                        exponentAdjust = 4 * (leftDigits - 1);
                 } else {                // Cases 3 and 4
-                    exponentAdjust = -4*( rightDigits - signifLength + 1);
+                        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);
+                        return isNegative ? A2BC_NEGATIVE_ZERO : A2BC_POSITIVE_ZERO;
                 }
             }
 
             //  Extract Exponent
-            /*
-             * Use an int to read in the exponent value; this should
-             * provide more than sufficient range for non-contrived
-             * inputs.  If reading the exponent in as an int does
-             * overflow, examine the sign of the exponent and
-             * significand to determine what to do.
-             */
+                //
+                // 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("+");
+                boolean positiveExponent = (group8 == null) || group8.equals("+");
             long unsignedRawExponent;
             try {
                 unsignedRawExponent = Integer.parseInt(m.group(9));
             }
             catch (NumberFormatException e) {

@@ -2064,62 +2132,61 @@
                 //
                 //                      significand
                 //                      +               -
                 // exponent     +       +infinity       -infinity
                 //              -       +0.0            -0.0
-                return new FloatingDecimal(sign * (positiveExponent ?
-                                                   Double.POSITIVE_INFINITY : 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 ;
+                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;
+                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.
-             */
+                //
+                // 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]
+                    // exponent += 0
+                } else if (leadingDigit <= 3) { // [2, 3]
                 significand |= leadingDigit << 51;
                 nextShift = 52 - 5;
                 exponent += 1;
-            }
-            else if (leadingDigit <= 7) { // [4, 7]
+                } else if (leadingDigit <= 7) { // [4, 7]
                 significand |= leadingDigit << 50;
                 nextShift = 52 - 6;
                 exponent += 2;
-            }
-            else if (leadingDigit <= 15) { // [8, f]
+                } else if (leadingDigit <= 15) { // [8, f]
                 significand |= leadingDigit << 49;
                 nextShift = 52 - 7;
                 exponent += 3;
             } else {
                 throw new AssertionError("Result from digit conversion too large!");

@@ -2130,42 +2197,41 @@
 
             // 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.
-             */
+                //
+                // 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;
+                for (i = 1;
                 i < signifLength && nextShift >= 0;
                 i++) {
                 long currentDigit = getHexDigit(significandString, i);
                 significand |= (currentDigit << nextShift);
-                nextShift-=4;
+                    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
+                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
+                    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;

@@ -2173,19 +2239,19 @@
 
                 case -2:
                     // two bits need to be copied in; can
                     // set round and start sticky
                     significand |= ((currentDigit & 0xCL) >> 2);
-                    round = (currentDigit &0x2L)  != 0L;
+                            round = (currentDigit & 0x2L) != 0L;
                     sticky = (currentDigit & 0x1L) != 0;
                     break;
 
                 case -3:
                     // one bit needs to be copied in
-                    significand |= ((currentDigit & 0x8L)>>3);
+                            significand |= ((currentDigit & 0x8L) >> 3);
                     // Now set round and start sticky, if possible
-                    round = (currentDigit &0x4L)  != 0L;
+                            round = (currentDigit & 0x4L) != 0L;
                     sticky = (currentDigit & 0x3L) != 0;
                     break;
 
                 case -4:
                     // all bits copied into significand; set

@@ -2204,26 +2270,24 @@
 
                 // 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);
+                    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);
+                    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

@@ -2235,30 +2299,30 @@
                     // 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))
+                        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 )) {
+                        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);
+                            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.
-                         */
+                            //
+                            // 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

@@ -2266,173 +2330,177 @@
                         // check:
                         // -1075 +1074 + 1 = 0
                         // -1023 +1074 + 1 = 52
 
                         int bitsDiscarded = 53 -
-                            ((int)exponent - DoubleConsts.MIN_SUB_EXPONENT + 1);
+                                    ((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;
+                            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 ) ;
+                                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))
+                            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;
+                    //
+                    // 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 )) {
-                    incremented = true;
+                    if ((leastZero && round && sticky) ||
+                            ((!leastZero) && round)) {
                     significand++;
                 }
 
-                FloatingDecimal fd = new FloatingDecimal(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 ) ){
+                    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 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 (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;
+                                        roundDir = 1;
                                 }
-                            }
-                            else { // prerounding lsb is 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;
+                                    if (round) {
+                                        roundDir = -1;
                             }
                         }
                     }
                 }
-
-                fd.fromHex = true;
-                return fd;
+                    }
+                    return new PreparedASCIIToBinaryBuffer(value,roundDir);
             }
         }
     }
 
     /**
-     * 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) {
         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;
     }
-
-
 }