changeset 1506:549f06563f1c

8010803: Number to String conversion functionality overhaul Reviewed-by: attila, lagergren
author hannesw
date Wed, 11 Nov 2015 15:22:14 +0100
parents e5ed16b0ae71
children a661018d34b8
files make/build.xml src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeNumber.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/JSType.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/NumberToString.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/doubleconv/Bignum.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/doubleconv/BignumDtoa.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/doubleconv/CachedPowers.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/doubleconv/DiyFp.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/doubleconv/DoubleConversion.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/doubleconv/DtoaBuffer.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/doubleconv/DtoaMode.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/doubleconv/FastDtoa.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/doubleconv/FixedDtoa.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/doubleconv/IeeeDouble.java test/script/basic/JDK-8062141.js.EXPECTED test/script/basic/NASHORN-389.js test/script/basic/NASHORN-389.js.EXPECTED test/src/jdk/nashorn/internal/runtime/doubleconv/test/BignumDtoaTest.java test/src/jdk/nashorn/internal/runtime/doubleconv/test/BignumTest.java test/src/jdk/nashorn/internal/runtime/doubleconv/test/DiyFpTest.java test/src/jdk/nashorn/internal/runtime/doubleconv/test/FastDtoaTest.java test/src/jdk/nashorn/internal/runtime/doubleconv/test/FixedDtoaTest.java test/src/jdk/nashorn/internal/runtime/doubleconv/test/IeeeDoubleTest.java test/src/jdk/nashorn/internal/runtime/doubleconv/test/resources/gay-fixed.txt test/src/jdk/nashorn/internal/runtime/doubleconv/test/resources/gay-precision.txt test/src/jdk/nashorn/internal/runtime/doubleconv/test/resources/gay-shortest.txt
diffstat 26 files changed, 307175 insertions(+), 799 deletions(-) [+]
line wrap: on
line diff
--- a/make/build.xml	Wed Nov 11 14:54:09 2015 +0100
+++ b/make/build.xml	Wed Nov 11 15:22:14 2015 +0100
@@ -311,6 +311,10 @@
        <fileset dir="${test.src.dir}/jdk/nashorn/internal/runtime/test/resources"/>
     </copy>
 
+    <copy todir="${build.test.classes.dir}/jdk/nashorn/internal/runtime/doubleconv/test/resources">
+      <fileset dir="${test.src.dir}/jdk/nashorn/internal/runtime/doubleconv/test/resources"/>
+    </copy>
+
     <copy todir="${build.test.classes.dir}/jdk/nashorn/api/scripting/test/resources">
        <fileset dir="${test.src.dir}/jdk/nashorn/api/scripting/test/resources"/>
     </copy>
@@ -436,6 +440,7 @@
           <include name="**/runtime/test/*Test.class"/>
           <include name="**/runtime/regexp/test/*Test.class"/>
           <include name="**/runtime/regexp/joni/test/*Test.class"/>
+          <include name="**/runtime/doubleconv/test/*Test.class"/>
           <include name="**/framework/*Test.class"/>
      </fileset>
   </target>
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeNumber.java	Wed Nov 11 14:54:09 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeNumber.java	Wed Nov 11 15:22:14 2015 +0100
@@ -49,6 +49,7 @@
 import jdk.nashorn.internal.runtime.PropertyMap;
 import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.ScriptRuntime;
+import jdk.nashorn.internal.runtime.doubleconv.DoubleConversion;
 import jdk.nashorn.internal.runtime.linker.PrimitiveLookup;
 
 /**
@@ -184,13 +185,7 @@
             return JSType.toString(x);
         }
 
-        final NumberFormat format = NumberFormat.getNumberInstance(Locale.US);
-        format.setMinimumFractionDigits(fractionDigits);
-        format.setMaximumFractionDigits(fractionDigits);
-        format.setGroupingUsed(false);
-        format.setRoundingMode(RoundingMode.HALF_UP);
-
-        return format.format(x);
+        return DoubleConversion.toFixed(x, fractionDigits);
     }
 
     /**
@@ -267,7 +262,7 @@
             return "0";
         }
 
-        return fixExponent(String.format(Locale.US, "%." + p + "g", x), false);
+        return DoubleConversion.toPrecision(x, p);
     }
 
     /**
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/JSType.java	Wed Nov 11 14:54:09 2015 +0100
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/JSType.java	Wed Nov 11 15:22:14 2015 +0100
@@ -42,6 +42,7 @@
 import jdk.nashorn.internal.objects.Global;
 import jdk.nashorn.internal.parser.Lexer;
 import jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator;
+import jdk.nashorn.internal.runtime.doubleconv.DoubleConversion;
 import jdk.nashorn.internal.runtime.linker.Bootstrap;
 
 /**
@@ -687,7 +688,7 @@
             return "NaN";
         }
 
-        return NumberToString.stringFor(num);
+        return DoubleConversion.toShortestString(num);
     }
 
     /**
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/NumberToString.java	Wed Nov 11 14:54:09 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,786 +0,0 @@
-/*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.nashorn.internal.runtime;
-
-import java.math.BigInteger;
-
-/**
- * JavaScript number to string conversion, refinement of sun.misc.FloatingDecimal.
- */
-public final class NumberToString {
-    /** Is not a number flag */
-    private final boolean isNaN;
-
-    /** Is a negative number flag. */
-    private boolean isNegative;
-
-    /** Decimal exponent value (for E notation.) */
-    private int decimalExponent;
-
-    /** Actual digits. */
-    private char digits[];
-
-    /** Number of digits to use. (nDigits <= digits.length). */
-    private int nDigits;
-
-    /*
-     * IEEE-754 constants.
-     */
-
-    //private static final long   signMask           = 0x8000000000000000L;
-    private static final int    expMask            = 0x7FF;
-    private static final long   fractMask          = 0x000F_FFFF_FFFF_FFFFL;
-    private static final int    expShift           = 52;
-    private static final int    expBias            = 1_023;
-    private static final long   fractHOB           = (1L << expShift);
-    private static final long   expOne             = ((long)expBias) << expShift;
-    private static final int    maxSmallBinExp     = 62;
-    private static final int    minSmallBinExp     = -(63 / 3);
-
-    /** Powers of 5 fitting a long. */
-    private static final long powersOf5[] = {
-        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(longPowers5[i])).
-    private static final int nBitsPowerOf5[] = {
-        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
-    };
-
-    /** Digits used for infinity result. */
-    private static final char infinityDigits[]   = { 'I', 'n', 'f', 'i', 'n', 'i', 't', 'y' };
-
-    /** Digits used for NaN result. */
-    private static final char nanDigits[]        = { 'N', 'a', 'N' };
-
-    /** Zeros used to pad result. */
-    private static final char zeroes[]           = { '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0' };
-
-
-    /**
-     * Convert a number into a JavaScript string.
-     * @param value Double to convert.
-     * @return JavaScript formated number.
-     */
-    public static String stringFor(final double value) {
-        return new NumberToString(value).toString();
-    }
-
-    /*
-     * Constructor.
-     */
-
-    private NumberToString(final double value) {
-        // Double as bits.
-        long bits = Double.doubleToLongBits(value);
-
-        // Get upper word.
-        final int upper = (int)(bits >> 32);
-
-        // Detect sign.
-        isNegative = upper < 0;
-
-        // Extract exponent.
-        int exponent = (upper >> (expShift - 32)) & expMask;
-
-        // Clear sign and exponent.
-        bits &= fractMask;
-
-        // Detect NaN.
-        if (exponent == expMask) {
-            isNaN = true;
-
-            // Detect Infinity.
-            if (bits == 0L) {
-                digits =  infinityDigits;
-            } else {
-                digits = nanDigits;
-                isNegative = false;
-            }
-
-            nDigits = digits.length;
-
-            return;
-        }
-
-        // We have a working double.
-        isNaN = false;
-
-        int nSignificantBits;
-
-        // Detect denormalized value.
-        if (exponent == 0) {
-            // Detect zero value.
-            if (bits == 0L) {
-                decimalExponent = 0;
-                digits = zeroes;
-                nDigits = 1;
-
-                return;
-            }
-
-            // Normalize value, using highest significant bit as HOB.
-            while ((bits & fractHOB) == 0L) {
-                bits <<= 1;
-                exponent -= 1;
-            }
-
-            // Compute number of significant bits.
-            nSignificantBits = expShift + exponent +1;
-            // Bias exponent by HOB.
-            exponent += 1;
-        } else {
-            // Add implicit HOB.
-            bits |= fractHOB;
-            // Compute number of significant bits.
-            nSignificantBits = expShift + 1;
-        }
-
-        // Unbias exponent (represents bit shift).
-        exponent -= expBias;
-
-        // Determine the number of significant bits in the fraction.
-        final int nFractBits = countSignificantBits(bits);
-
-        // Number of bits to the right of the decimal.
-        final int nTinyBits = Math.max(0, nFractBits - exponent - 1);
-
-        // Computed decimal exponent.
-        int decExponent;
-
-        if (exponent <= maxSmallBinExp && exponent >= minSmallBinExp) {
-            // Look more closely at the number to decide if,
-            // with scaling by 10^nTinyBits, the result will fit in
-            // a long.
-            if (nTinyBits < powersOf5.length && (nFractBits + nBitsPowerOf5[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.
-                 */
-
-                if (nTinyBits == 0) {
-                    long halfULP;
-
-                    if (exponent > nSignificantBits) {
-                        halfULP = 1L << (exponent - nSignificantBits - 1);
-                    } else {
-                        halfULP = 0L;
-                    }
-
-                    if (exponent >= expShift) {
-                        bits <<= exponent - expShift;
-                    } else {
-                        bits >>>= expShift - exponent;
-                    }
-
-                    // Discard non-significant low-order bits, while rounding,
-                    // up to insignificant value.
-                    int i;
-                    for (i = 0; halfULP >= 10L; i++) {
-                        halfULP /= 10L;
-                    }
-
-                    /**
-                     * This is the easy subcase --
-                     * all the significant bits, after scaling, are held in bits.
-                     * isNegative and decExponent tell us what processing and scaling
-                     * has already been done. Exceptional cases have already been
-                     * stripped out.
-                     * In particular:
-                     *      bits is a finite number (not Infinite, nor NaN)
-                     *      bits > 0L (not zero, nor negative).
-                     *
-                     * The only reason that we develop the digits here, rather than
-                     * calling on Long.toString() is that we can do it a little faster,
-                     * and besides want to treat trailing 0s specially. If Long.toString
-                     * changes, we should re-evaluate this strategy!
-                     */
-
-                    int decExp = 0;
-
-                    if (i != 0) {
-                         // 10^i == 5^i * 2^i
-                        final long powerOf10 = powersOf5[i] << i;
-                        final long residue = bits % powerOf10;
-                        bits /= powerOf10;
-                        decExp += i;
-
-                        if (residue >= (powerOf10 >> 1)) {
-                            // Round up based on the low-order bits we're discarding.
-                            bits++;
-                        }
-                    }
-
-                    int ndigits = 20;
-                    final char[] digits0 = new char[26];
-                    int digitno = ndigits - 1;
-                    int c = (int)(bits % 10L);
-                    bits /= 10L;
-
-                    while (c == 0) {
-                        decExp++;
-                        c = (int)(bits % 10L);
-                        bits /= 10L;
-                    }
-
-                    while (bits != 0L) {
-                        digits0[digitno--] = (char)(c + '0');
-                        decExp++;
-                        c = (int)(bits % 10L);
-                        bits /= 10;
-                    }
-
-                    digits0[digitno] = (char)(c + '0');
-
-                    ndigits -= digitno;
-                    final char[] result = new char[ndigits];
-                    System.arraycopy(digits0, digitno, result, 0, ndigits);
-
-                    this.digits          = result;
-                    this.decimalExponent = decExp + 1;
-                    this.nDigits         = ndigits;
-
-                    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.
-         */
-        final double d2 = Double.longBitsToDouble(expOne | (bits & ~fractHOB));
-        decExponent = (int)Math.floor((d2 - 1.5D) * 0.289529654D + 0.176091259D + exponent * 0.301029995663981D);
-
-        // Powers of 2 and powers of 5, respectively, in B.
-        final int B5 = Math.max(0, -decExponent);
-        int B2 = B5 + nTinyBits + exponent;
-
-        // Powers of 2 and powers of 5, respectively, in S.
-        final int S5 = Math.max(0, decExponent);
-        int S2 = S5 + nTinyBits;
-
-        // Powers of 2 and powers of 5, respectively, in M.
-        final int M5 = B5;
-        int 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
-         * BigInteger. The resulting whole number will be
-         *      d * 2^(nFractBits - 1 - binExp).
-         */
-
-        bits >>>= expShift + 1 - nFractBits;
-        B2 -= nFractBits - 1;
-        final int common2factor = Math.min(B2, S2);
-        B2 -= common2factor;
-        S2 -= common2factor;
-        M2 -= common2factor;
-
-        /*
-         * HACK!!For exact powers of two, the next smallest number
-         * is only half as far away as we think (because the meaning of
-         * ULP changes at power-of-two bounds) for this reason, we
-         * hack M2. Hope this works.
-         */
-        if (nFractBits == 1) {
-            M2 -= 1;
-        }
-
-        if (M2 < 0) {
-            // Oops.  Since we cannot scale M down far enough,
-            // we must scale the other values up.
-            B2 -= M2;
-            S2 -= M2;
-            M2 =  0;
-        }
-
-        /*
-         * Construct, Scale, iterate.
-         * Some day, we'll write a stopping test that takes
-         * account of the asymmetry of the spacing of floating-point
-         * numbers below perfect powers of 2
-         * 26 Sept 96 is not that day.
-         * So we use a symmetric test.
-         */
-
-        final char digits0[] = this.digits = new char[32];
-        int  ndigit;
-        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 BigInteger 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!
-         */
-
-        // Binary digits needed to represent B, approx.
-        final int Bbits = nFractBits + B2 + ((B5 < nBitsPowerOf5.length) ? nBitsPowerOf5[B5] : (B5*3));
-        // Binary digits needed to represent 10*S, approx.
-        final int tenSbits = S2 + 1 + (((S5 + 1) < nBitsPowerOf5.length) ? nBitsPowerOf5[(S5 + 1)] : ((S5 + 1) * 3));
-
-        if (Bbits < 64 && tenSbits < 64) {
-            long b = (bits * powersOf5[B5]) << B2;
-            final long s = powersOf5[S5] << S2;
-            long m = powersOf5[M5] << M2;
-            final long tens = s * 10L;
-
-            /*
-             * Unroll the first iteration. If our decExp estimate
-             * was too high, our first quotient will be zero. In this
-             * case, we discard it and decrement decExp.
-             */
-
-            ndigit = 0;
-            q = (int)(b / s);
-            b = 10L * (b % s);
-            m *= 10L;
-            low  = b <  m;
-            high = (b + m) > tens;
-
-            if (q == 0 && !high) {
-                // Ignore leading zero.
-                decExponent--;
-            } else {
-                digits0[ndigit++] = (char)('0' + q);
-            }
-
-            if (decExponent < -3 || decExponent >= 8) {
-                high = low = false;
-            }
-
-            while (!low && !high) {
-                q = (int)(b / s);
-                b = 10 * (b % s);
-                m *= 10;
-
-                if (m > 0L) {
-                    low  = b < m;
-                    high = (b + m) > tens;
-                } else {
-                    low = true;
-                    high = true;
-                }
-
-                if (low && q == 0) {
-                    break;
-                }
-                digits0[ndigit++] = (char)('0' + q);
-            }
-
-            lowDigitDifference = (b << 1) - tens;
-        } else {
-            /*
-             * We must do BigInteger arithmetic.
-             * First, construct our BigInteger initial values.
-             */
-
-            BigInteger Bval = multiplyPowerOf5And2(BigInteger.valueOf(bits), B5, B2);
-            BigInteger Sval = constructPowerOf5And2(S5, S2);
-            BigInteger Mval = constructPowerOf5And2(M5, M2);
-
-
-            // Normalize so that BigInteger division works better.
-            final int shiftBias = Long.numberOfLeadingZeros(bits) - 4;
-            Bval = Bval.shiftLeft(shiftBias);
-            Mval = Mval.shiftLeft(shiftBias);
-            Sval = Sval.shiftLeft(shiftBias);
-            final BigInteger tenSval = Sval.multiply(BigInteger.TEN);
-
-            /*
-             * 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;
-
-            BigInteger[] quoRem = Bval.divideAndRemainder(Sval);
-            q    = quoRem[0].intValue();
-            Bval = quoRem[1].multiply(BigInteger.TEN);
-            Mval = Mval.multiply(BigInteger.TEN);
-            low  = (Bval.compareTo(Mval) < 0);
-            high = (Bval.add(Mval).compareTo(tenSval) > 0);
-
-            if (q == 0 && !high) {
-                // Ignore leading zero.
-                decExponent--;
-            } else {
-                digits0[ndigit++] = (char)('0' + q);
-            }
-
-            if (decExponent < -3 || decExponent >= 8) {
-                high = low = false;
-            }
-
-            while(!low && !high) {
-                quoRem = Bval.divideAndRemainder(Sval);
-                q = quoRem[0].intValue();
-                Bval = quoRem[1].multiply(BigInteger.TEN);
-                Mval = Mval.multiply(BigInteger.TEN);
-                low  = (Bval.compareTo(Mval) < 0);
-                high = (Bval.add(Mval).compareTo(tenSval) > 0);
-
-                if (low && q == 0) {
-                    break;
-                }
-                digits0[ndigit++] = (char)('0' + q);
-            }
-
-            if (high && low) {
-                Bval = Bval.shiftLeft(1);
-                lowDigitDifference = Bval.compareTo(tenSval);
-            } else {
-                lowDigitDifference = 0L;
-            }
-        }
-
-        this.decimalExponent = decExponent + 1;
-        this.digits          = digits0;
-        this.nDigits         = ndigit;
-
-        /*
-         * Last digit gets rounded based on stopping condition.
-         */
-
-        if (high) {
-            if (low) {
-                if (lowDigitDifference == 0L) {
-                    // it's a tie!
-                    // choose based on which digits we like.
-                    if ((digits0[nDigits - 1] & 1) != 0) {
-                        roundup();
-                    }
-                } else if (lowDigitDifference > 0) {
-                    roundup();
-                }
-            } else {
-                roundup();
-            }
-        }
-    }
-
-    /**
-     * Count number of significant bits.
-     * @param bits Double's fraction.
-     * @return Number of significant bits.
-     */
-    private static int countSignificantBits(final long bits) {
-        if (bits != 0) {
-            return 64 - Long.numberOfLeadingZeros(bits) - Long.numberOfTrailingZeros(bits);
-        }
-
-        return 0;
-    }
-
-    /*
-     * Cache big powers of 5 handy for future reference.
-     */
-    private static BigInteger powerOf5Cache[];
-
-    /**
-     * Determine the largest power of 5 needed (as BigInteger.)
-     * @param power Power of 5.
-     * @return BigInteger of power of 5.
-     */
-    private static BigInteger bigPowerOf5(final int power) {
-        if (powerOf5Cache == null) {
-            powerOf5Cache = new BigInteger[power + 1];
-        } else if (powerOf5Cache.length <= power) {
-            final BigInteger t[] = new BigInteger[ power+1 ];
-            System.arraycopy(powerOf5Cache, 0, t, 0, powerOf5Cache.length);
-            powerOf5Cache = t;
-        }
-
-        if (powerOf5Cache[power] != null) {
-            return powerOf5Cache[power];
-        } else if (power < powersOf5.length) {
-            return powerOf5Cache[power] = BigInteger.valueOf(powersOf5[power]);
-        } else {
-            // Construct the value recursively.
-            // 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
-            final int q = power >> 1;
-            final int r = power - q;
-            BigInteger bigQ = powerOf5Cache[q];
-
-            if (bigQ == null) {
-                bigQ = bigPowerOf5(q);
-            }
-
-            if (r < powersOf5.length) {
-                return (powerOf5Cache[power] = bigQ.multiply(BigInteger.valueOf(powersOf5[r])));
-            }
-            BigInteger bigR = powerOf5Cache[ r ];
-
-            if (bigR == null) {
-                bigR = bigPowerOf5(r);
-            }
-
-            return (powerOf5Cache[power] = bigQ.multiply(bigR));
-        }
-    }
-
-    /**
-     * Multiply BigInteger by powers of 5 and 2 (i.e., 10)
-     * @param value Value to multiply.
-     * @param p5    Power of 5.
-     * @param p2    Power of 2.
-     * @return Result.
-     */
-    private static BigInteger multiplyPowerOf5And2(final BigInteger value, final int p5, final int p2) {
-        BigInteger returnValue = value;
-
-        if (p5 != 0) {
-            returnValue = returnValue.multiply(bigPowerOf5(p5));
-        }
-
-        if (p2 != 0) {
-            returnValue = returnValue.shiftLeft(p2);
-        }
-
-        return returnValue;
-    }
-
-    /**
-     * Construct a BigInteger power of 5 and 2 (i.e., 10)
-     * @param p5    Power of 5.
-     * @param p2    Power of 2.
-     * @return Result.
-     */
-    private static BigInteger constructPowerOf5And2(final int p5, final int p2) {
-        BigInteger v = bigPowerOf5(p5);
-
-        if (p2 != 0) {
-            v = v.shiftLeft(p2);
-        }
-
-        return v;
-    }
-
-    /**
-     * Round up last digit by adding 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)];
-
-        while (q == '9' && i > 0) {
-            if (decimalExponent < 0) {
-                nDigits--;
-            } else {
-                digits[i] = '0';
-            }
-
-            q = digits[--i];
-        }
-
-        if (q == '9') {
-            // Carryout! High-order 1, rest 0s, larger exp.
-            decimalExponent += 1;
-            digits[0] = '1';
-
-            return;
-        }
-
-        digits[i] = (char)(q + 1);
-    }
-
-    /**
-     * Format final number string.
-     * @return Formatted string.
-     */
-    @Override
-    public String toString() {
-        final StringBuilder sb = new StringBuilder(32);
-
-        if (isNegative) {
-            sb.append('-');
-        }
-
-        if (isNaN) {
-            sb.append(digits, 0, nDigits);
-        } else {
-            if (decimalExponent > 0 && decimalExponent <= 21) {
-                final int charLength = Math.min(nDigits, decimalExponent);
-                sb.append(digits, 0, charLength);
-
-                if (charLength < decimalExponent) {
-                    sb.append(zeroes, 0, decimalExponent - charLength);
-                } else if (charLength < nDigits) {
-                    sb.append('.');
-                    sb.append(digits, charLength, nDigits - charLength);
-                }
-            } else if (decimalExponent <=0 && decimalExponent > -6) {
-                sb.append('0');
-                sb.append('.');
-
-                if (decimalExponent != 0) {
-                    sb.append(zeroes, 0, -decimalExponent);
-                }
-
-                sb.append(digits, 0, nDigits);
-            } else {
-                sb.append(digits[0]);
-
-                if (nDigits > 1) {
-                    sb.append('.');
-                    sb.append(digits, 1, nDigits - 1);
-                }
-
-                sb.append('e');
-                final int exponent;
-                int e;
-
-                if (decimalExponent <= 0) {
-                    sb.append('-');
-                    exponent = e = -decimalExponent + 1;
-                } else {
-                    sb.append('+');
-                    exponent = e = decimalExponent - 1;
-                }
-
-                if (exponent > 99) {
-                    sb.append((char)(e / 100 + '0'));
-                    e %= 100;
-                }
-
-                if (exponent > 9) {
-                    sb.append((char)(e / 10 + '0'));
-                    e %= 10;
-                }
-
-                sb.append((char)(e + '0'));
-            }
-        }
-
-        return sb.toString();
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/doubleconv/Bignum.java	Wed Nov 11 15:22:14 2015 +0100
@@ -0,0 +1,842 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// This file is available under and governed by the GNU General Public
+// License version 2 only, as published by the Free Software Foundation.
+// However, the following notice accompanied the original version of this
+// file:
+//
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package jdk.nashorn.internal.runtime.doubleconv;
+
+import java.util.Arrays;
+
+class Bignum {
+
+    // 3584 = 128 * 28. We can represent 2^3584 > 10^1000 accurately.
+    // This bignum can encode much bigger numbers, since it contains an
+    // exponent.
+    static final int kMaxSignificantBits = 3584;
+
+    static final int kChunkSize = 32;       // size of int
+    static final int kDoubleChunkSize = 64; // size of long
+    // With bigit size of 28 we loose some bits, but a double still fits easily
+    // into two ints, and more importantly we can use the Comba multiplication.
+    static final int kBigitSize = 28;
+    static final int kBigitMask = (1 << kBigitSize) - 1;
+    // Every instance allocates kbigitLength ints on the stack. Bignums cannot
+    // grow. There are no checks if the stack-allocated space is sufficient.
+    static final int kBigitCapacity = kMaxSignificantBits / kBigitSize;
+
+    private int[] bigits_ = new int[kBigitCapacity];
+    // A vector backed by bigits_buffer_. This way accesses to the array are
+    // checked for out-of-bounds errors.
+    // Vector<int> bigits_;
+    private int used_digits_;
+    // The Bignum's value equals value(bigits_) * 2^(exponent_ * kBigitSize).
+    private int exponent_;
+
+    Bignum() {}
+
+    void times10() { multiplyByUInt32(10); }
+
+    static boolean equal(final Bignum a, final Bignum b) {
+        return compare(a, b) == 0;
+    }
+    static boolean lessEqual(final Bignum a, final Bignum b) {
+        return compare(a, b) <= 0;
+    }
+    static boolean less(final Bignum a, final Bignum b) {
+        return compare(a, b) < 0;
+    }
+
+    // Returns a + b == c
+    static boolean plusEqual(final Bignum a, final Bignum b, final Bignum c) {
+        return plusCompare(a, b, c) == 0;
+    }
+    // Returns a + b <= c
+    static boolean plusLessEqual(final Bignum a, final Bignum b, final Bignum c) {
+        return plusCompare(a, b, c) <= 0;
+    }
+    // Returns a + b < c
+    static boolean plusLess(final Bignum a, final Bignum b, final Bignum c) {
+        return plusCompare(a, b, c) < 0;
+    }
+
+    private void ensureCapacity(final int size) {
+        if (size > kBigitCapacity) {
+            throw new RuntimeException();
+        }
+    }
+
+    // BigitLength includes the "hidden" digits encoded in the exponent.
+    int bigitLength() { return used_digits_ + exponent_; }
+
+    // Guaranteed to lie in one Bigit.
+    void assignUInt16(final char value) {
+        assert (kBigitSize >= 16);
+        zero();
+        if (value == 0) return;
+
+        ensureCapacity(1);
+        bigits_[0] = value;
+        used_digits_ = 1;
+    }
+
+
+    void assignUInt64(long value) {
+        final  int kUInt64Size = 64;
+
+        zero();
+        if (value == 0) return;
+
+        final int needed_bigits = kUInt64Size / kBigitSize + 1;
+        ensureCapacity(needed_bigits);
+        for (int i = 0; i < needed_bigits; ++i) {
+            bigits_[i] = (int) (value & kBigitMask);
+            value = value >>> kBigitSize;
+        }
+        used_digits_ = needed_bigits;
+        clamp();
+    }
+
+
+    void assignBignum(final Bignum other) {
+        exponent_ = other.exponent_;
+        for (int i = 0; i < other.used_digits_; ++i) {
+            bigits_[i] = other.bigits_[i];
+        }
+        // Clear the excess digits (if there were any).
+        for (int i = other.used_digits_; i < used_digits_; ++i) {
+            bigits_[i] = 0;
+        }
+        used_digits_ = other.used_digits_;
+    }
+
+
+    static long readUInt64(final String str,
+                           final int from,
+                           final int digits_to_read) {
+        long result = 0;
+        for (int i = from; i < from + digits_to_read; ++i) {
+            final int digit = str.charAt(i) - '0';
+            assert (0 <= digit && digit <= 9);
+            result = result * 10 + digit;
+        }
+        return result;
+    }
+
+
+    void assignDecimalString(final String str) {
+        // 2^64 = 18446744073709551616 > 10^19
+        final int kMaxUint64DecimalDigits = 19;
+        zero();
+        int length = str.length();
+        int pos = 0;
+        // Let's just say that each digit needs 4 bits.
+        while (length >= kMaxUint64DecimalDigits) {
+            final long digits = readUInt64(str, pos, kMaxUint64DecimalDigits);
+            pos += kMaxUint64DecimalDigits;
+            length -= kMaxUint64DecimalDigits;
+            multiplyByPowerOfTen(kMaxUint64DecimalDigits);
+            addUInt64(digits);
+        }
+        final long digits = readUInt64(str, pos, length);
+        multiplyByPowerOfTen(length);
+        addUInt64(digits);
+        clamp();
+    }
+
+
+    static int hexCharValue(final char c) {
+        if ('0' <= c && c <= '9') return c - '0';
+        if ('a' <= c && c <= 'f') return 10 + c - 'a';
+        assert ('A' <= c && c <= 'F');
+        return 10 + c - 'A';
+    }
+
+
+    void assignHexString(final String str) {
+        zero();
+        final int length = str.length();
+
+        final int needed_bigits = length * 4 / kBigitSize + 1;
+        ensureCapacity(needed_bigits);
+        int string_index = length - 1;
+        for (int i = 0; i < needed_bigits - 1; ++i) {
+            // These bigits are guaranteed to be "full".
+            int current_bigit = 0;
+            for (int j = 0; j < kBigitSize / 4; j++) {
+                current_bigit += hexCharValue(str.charAt(string_index--)) << (j * 4);
+            }
+            bigits_[i] = current_bigit;
+        }
+        used_digits_ = needed_bigits - 1;
+
+        int most_significant_bigit = 0;  // Could be = 0;
+        for (int j = 0; j <= string_index; ++j) {
+            most_significant_bigit <<= 4;
+            most_significant_bigit += hexCharValue(str.charAt(j));
+        }
+        if (most_significant_bigit != 0) {
+            bigits_[used_digits_] = most_significant_bigit;
+            used_digits_++;
+        }
+        clamp();
+    }
+
+
+    void addUInt64(final long operand) {
+        if (operand == 0) return;
+        final Bignum other = new Bignum();
+        other.assignUInt64(operand);
+        addBignum(other);
+    }
+
+
+    void addBignum(final Bignum other) {
+        assert (isClamped());
+        assert (other.isClamped());
+
+        // If this has a greater exponent than other append zero-bigits to this.
+        // After this call exponent_ <= other.exponent_.
+        align(other);
+
+        // There are two possibilities:
+        //   aaaaaaaaaaa 0000  (where the 0s represent a's exponent)
+        //     bbbbb 00000000
+        //   ----------------
+        //   ccccccccccc 0000
+        // or
+        //    aaaaaaaaaa 0000
+        //  bbbbbbbbb 0000000
+        //  -----------------
+        //  cccccccccccc 0000
+        // In both cases we might need a carry bigit.
+
+        ensureCapacity(1 + Math.max(bigitLength(), other.bigitLength()) - exponent_);
+        int carry = 0;
+        int bigit_pos = other.exponent_ - exponent_;
+        assert (bigit_pos >= 0);
+        for (int i = 0; i < other.used_digits_; ++i) {
+            final int sum = bigits_[bigit_pos] + other.bigits_[i] + carry;
+            bigits_[bigit_pos] = sum & kBigitMask;
+            carry = sum >>> kBigitSize;
+            bigit_pos++;
+        }
+
+        while (carry != 0) {
+            final int sum = bigits_[bigit_pos] + carry;
+            bigits_[bigit_pos] = sum & kBigitMask;
+            carry = sum >>> kBigitSize;
+            bigit_pos++;
+        }
+        used_digits_ = Math.max(bigit_pos, used_digits_);
+        assert (isClamped());
+    }
+
+
+    void subtractBignum(final Bignum other) {
+        assert (isClamped());
+        assert (other.isClamped());
+        // We require this to be bigger than other.
+        assert (lessEqual(other, this));
+
+        align(other);
+
+        final int offset = other.exponent_ - exponent_;
+        int borrow = 0;
+        int i;
+        for (i = 0; i < other.used_digits_; ++i) {
+            assert ((borrow == 0) || (borrow == 1));
+            final int difference = bigits_[i + offset] - other.bigits_[i] - borrow;
+            bigits_[i + offset] = difference & kBigitMask;
+            borrow = difference >>> (kChunkSize - 1);
+        }
+        while (borrow != 0) {
+            final int difference = bigits_[i + offset] - borrow;
+            bigits_[i + offset] = difference & kBigitMask;
+            borrow = difference >>> (kChunkSize - 1);
+            ++i;
+        }
+        clamp();
+    }
+
+
+    void shiftLeft(final int shift_amount) {
+        if (used_digits_ == 0) return;
+        exponent_ += shift_amount / kBigitSize;
+        final int local_shift = shift_amount % kBigitSize;
+        ensureCapacity(used_digits_ + 1);
+        bigitsShiftLeft(local_shift);
+    }
+
+
+    void multiplyByUInt32(final int factor) {
+        if (factor == 1) return;
+        if (factor == 0) {
+            zero();
+            return;
+        }
+        if (used_digits_ == 0) return;
+
+        // The product of a bigit with the factor is of size kBigitSize + 32.
+        // Assert that this number + 1 (for the carry) fits into double int.
+        assert (kDoubleChunkSize >= kBigitSize + 32 + 1);
+        long carry = 0;
+        for (int i = 0; i < used_digits_; ++i) {
+            final long product = (factor & 0xFFFFFFFFL) * bigits_[i] + carry;
+            bigits_[i] = (int) (product & kBigitMask);
+            carry = product >>> kBigitSize;
+        }
+        while (carry != 0) {
+            ensureCapacity(used_digits_ + 1);
+            bigits_[used_digits_] = (int) (carry & kBigitMask);
+            used_digits_++;
+            carry >>>= kBigitSize;
+        }
+    }
+
+
+    void multiplyByUInt64(final long factor) {
+        if (factor == 1) return;
+        if (factor == 0) {
+            zero();
+            return;
+        }
+        assert (kBigitSize < 32);
+        long carry = 0;
+        final long low = factor & 0xFFFFFFFFL;
+        final long high = factor >>> 32;
+        for (int i = 0; i < used_digits_; ++i) {
+            final long product_low = low * bigits_[i];
+            final long product_high = high * bigits_[i];
+            final long tmp = (carry & kBigitMask) + product_low;
+            bigits_[i] = (int) (tmp & kBigitMask);
+            carry = (carry >>> kBigitSize) + (tmp >>> kBigitSize) +
+                    (product_high << (32 - kBigitSize));
+        }
+        while (carry != 0) {
+            ensureCapacity(used_digits_ + 1);
+            bigits_[used_digits_] = (int) (carry & kBigitMask);
+            used_digits_++;
+            carry >>>= kBigitSize;
+        }
+    }
+
+
+    void multiplyByPowerOfTen(final int exponent) {
+        final long kFive27 = 0x6765c793fa10079dL;
+        final int kFive1 = 5;
+        final int kFive2 = kFive1 * 5;
+        final int kFive3 = kFive2 * 5;
+        final int kFive4 = kFive3 * 5;
+        final int kFive5 = kFive4 * 5;
+        final int kFive6 = kFive5 * 5;
+        final int kFive7 = kFive6 * 5;
+        final int kFive8 = kFive7 * 5;
+        final int kFive9 = kFive8 * 5;
+        final int kFive10 = kFive9 * 5;
+        final int kFive11 = kFive10 * 5;
+        final int kFive12 = kFive11 * 5;
+        final int kFive13 = kFive12 * 5;
+        final int kFive1_to_12[] =
+                { kFive1, kFive2, kFive3, kFive4, kFive5, kFive6,
+                        kFive7, kFive8, kFive9, kFive10, kFive11, kFive12 };
+
+        assert (exponent >= 0);
+        if (exponent == 0) return;
+        if (used_digits_ == 0) return;
+
+        // We shift by exponent at the end just before returning.
+        int remaining_exponent = exponent;
+        while (remaining_exponent >= 27) {
+            multiplyByUInt64(kFive27);
+            remaining_exponent -= 27;
+        }
+        while (remaining_exponent >= 13) {
+            multiplyByUInt32(kFive13);
+            remaining_exponent -= 13;
+        }
+        if (remaining_exponent > 0) {
+            multiplyByUInt32(kFive1_to_12[remaining_exponent - 1]);
+        }
+        shiftLeft(exponent);
+    }
+
+
+    void square() {
+        assert (isClamped());
+        final int product_length = 2 * used_digits_;
+        ensureCapacity(product_length);
+
+        // Comba multiplication: compute each column separately.
+        // Example: r = a2a1a0 * b2b1b0.
+        //    r =  1    * a0b0 +
+        //        10    * (a1b0 + a0b1) +
+        //        100   * (a2b0 + a1b1 + a0b2) +
+        //        1000  * (a2b1 + a1b2) +
+        //        10000 * a2b2
+        //
+        // In the worst case we have to accumulate nb-digits products of digit*digit.
+        //
+        // Assert that the additional number of bits in a DoubleChunk are enough to
+        // sum up used_digits of Bigit*Bigit.
+        if ((1L << (2 * (kChunkSize - kBigitSize))) <= used_digits_) {
+            throw new RuntimeException("unimplemented");
+        }
+        long accumulator = 0;
+        // First shift the digits so we don't overwrite them.
+        final int copy_offset = used_digits_;
+        for (int i = 0; i < used_digits_; ++i) {
+            bigits_[copy_offset + i] = bigits_[i];
+        }
+        // We have two loops to avoid some 'if's in the loop.
+        for (int i = 0; i < used_digits_; ++i) {
+            // Process temporary digit i with power i.
+            // The sum of the two indices must be equal to i.
+            int bigit_index1 = i;
+            int bigit_index2 = 0;
+            // Sum all of the sub-products.
+            while (bigit_index1 >= 0) {
+                final int int1 = bigits_[copy_offset + bigit_index1];
+                final int int2 = bigits_[copy_offset + bigit_index2];
+                accumulator += ((long) int1) * int2;
+                bigit_index1--;
+                bigit_index2++;
+            }
+            bigits_[i] = (int) (accumulator & kBigitMask);
+            accumulator >>>= kBigitSize;
+        }
+        for (int i = used_digits_; i < product_length; ++i) {
+            int bigit_index1 = used_digits_ - 1;
+            int bigit_index2 = i - bigit_index1;
+            // Invariant: sum of both indices is again equal to i.
+            // Inner loop runs 0 times on last iteration, emptying accumulator.
+            while (bigit_index2 < used_digits_) {
+                final int int1 = bigits_[copy_offset + bigit_index1];
+                final int int2 = bigits_[copy_offset + bigit_index2];
+                accumulator += ((long) int1) * int2;
+                bigit_index1--;
+                bigit_index2++;
+            }
+            // The overwritten bigits_[i] will never be read in further loop iterations,
+            // because bigit_index1 and bigit_index2 are always greater
+            // than i - used_digits_.
+            bigits_[i] = (int) (accumulator & kBigitMask);
+            accumulator >>>= kBigitSize;
+        }
+        // Since the result was guaranteed to lie inside the number the
+        // accumulator must be 0 now.
+        assert (accumulator == 0);
+
+        // Don't forget to update the used_digits and the exponent.
+        used_digits_ = product_length;
+        exponent_ *= 2;
+        clamp();
+    }
+
+
+    void assignPowerUInt16(int base, final int power_exponent) {
+        assert (base != 0);
+        assert (power_exponent >= 0);
+        if (power_exponent == 0) {
+            assignUInt16((char) 1);
+            return;
+        }
+        zero();
+        int shifts = 0;
+        // We expect base to be in range 2-32, and most often to be 10.
+        // It does not make much sense to implement different algorithms for counting
+        // the bits.
+        while ((base & 1) == 0) {
+            base >>>= 1;
+            shifts++;
+        }
+        int bit_size = 0;
+        int tmp_base = base;
+        while (tmp_base != 0) {
+            tmp_base >>>= 1;
+            bit_size++;
+        }
+        final int final_size = bit_size * power_exponent;
+        // 1 extra bigit for the shifting, and one for rounded final_size.
+        ensureCapacity(final_size / kBigitSize + 2);
+
+        // Left to Right exponentiation.
+        int mask = 1;
+        while (power_exponent >= mask) mask <<= 1;
+
+        // The mask is now pointing to the bit above the most significant 1-bit of
+        // power_exponent.
+        // Get rid of first 1-bit;
+        mask >>>= 2;
+        long this_value = base;
+
+        boolean delayed_multipliciation = false;
+        final long max_32bits = 0xFFFFFFFFL;
+        while (mask != 0 && this_value <= max_32bits) {
+            this_value = this_value * this_value;
+            // Verify that there is enough space in this_value to perform the
+            // multiplication.  The first bit_size bits must be 0.
+            if ((power_exponent & mask) != 0) {
+                final long base_bits_mask =
+                        ~((1L << (64 - bit_size)) - 1);
+                final boolean high_bits_zero = (this_value & base_bits_mask) == 0;
+                if (high_bits_zero) {
+                    this_value *= base;
+                } else {
+                    delayed_multipliciation = true;
+                }
+            }
+            mask >>>= 1;
+        }
+        assignUInt64(this_value);
+        if (delayed_multipliciation) {
+            multiplyByUInt32(base);
+        }
+
+        // Now do the same thing as a bignum.
+        while (mask != 0) {
+            square();
+            if ((power_exponent & mask) != 0) {
+                multiplyByUInt32(base);
+            }
+            mask >>>= 1;
+        }
+
+        // And finally add the saved shifts.
+        shiftLeft(shifts * power_exponent);
+    }
+
+
+    // Precondition: this/other < 16bit.
+    char divideModuloIntBignum(final Bignum other) {
+        assert (isClamped());
+        assert (other.isClamped());
+        assert (other.used_digits_ > 0);
+
+        // Easy case: if we have less digits than the divisor than the result is 0.
+        // Note: this handles the case where this == 0, too.
+        if (bigitLength() < other.bigitLength()) {
+            return 0;
+        }
+
+        align(other);
+
+        char result = 0;
+
+        // Start by removing multiples of 'other' until both numbers have the same
+        // number of digits.
+        while (bigitLength() > other.bigitLength()) {
+            // This naive approach is extremely inefficient if `this` divided by other
+            // is big. This function is implemented for doubleToString where
+            // the result should be small (less than 10).
+            assert (other.bigits_[other.used_digits_ - 1] >= ((1 << kBigitSize) / 16));
+            assert (bigits_[used_digits_ - 1] < 0x10000);
+            // Remove the multiples of the first digit.
+            // Example this = 23 and other equals 9. -> Remove 2 multiples.
+            result += (bigits_[used_digits_ - 1]);
+            subtractTimes(other, bigits_[used_digits_ - 1]);
+        }
+
+        assert (bigitLength() == other.bigitLength());
+
+        // Both bignums are at the same length now.
+        // Since other has more than 0 digits we know that the access to
+        // bigits_[used_digits_ - 1] is safe.
+        final int this_bigit = bigits_[used_digits_ - 1];
+        final int other_bigit = other.bigits_[other.used_digits_ - 1];
+
+        if (other.used_digits_ == 1) {
+            // Shortcut for easy (and common) case.
+            final int quotient = Integer.divideUnsigned(this_bigit, other_bigit);
+            bigits_[used_digits_ - 1] = this_bigit - other_bigit * quotient;
+            assert (Integer.compareUnsigned(quotient, 0x10000) < 0);
+            result += quotient;
+            clamp();
+            return result;
+        }
+
+        final int division_estimate = Integer.divideUnsigned(this_bigit, (other_bigit + 1));
+        assert (Integer.compareUnsigned(division_estimate, 0x10000) < 0);
+        result += division_estimate;
+        subtractTimes(other, division_estimate);
+
+        if (other_bigit * (division_estimate + 1) > this_bigit) {
+            // No need to even try to subtract. Even if other's remaining digits were 0
+            // another subtraction would be too much.
+            return result;
+        }
+
+        while (lessEqual(other, this)) {
+            subtractBignum(other);
+            result++;
+        }
+        return result;
+    }
+
+
+    static int sizeInHexChars(int number) {
+        assert (number > 0);
+        int result = 0;
+        while (number != 0) {
+            number >>>= 4;
+            result++;
+        }
+        return result;
+    }
+
+
+    static char hexCharOfValue(final int value) {
+        assert (0 <= value && value <= 16);
+        if (value < 10) return (char) (value + '0');
+        return (char) (value - 10 + 'A');
+    }
+
+
+    String toHexString() {
+        assert (isClamped());
+        // Each bigit must be printable as separate hex-character.
+        assert (kBigitSize % 4 == 0);
+        final int kHexCharsPerBigit = kBigitSize / 4;
+
+        if (used_digits_ == 0) {
+            return "0";
+        }
+
+        final int needed_chars = (bigitLength() - 1) * kHexCharsPerBigit +
+                sizeInHexChars(bigits_[used_digits_ - 1]);
+        final StringBuilder buffer = new StringBuilder(needed_chars);
+        buffer.setLength(needed_chars);
+
+        int string_index = needed_chars - 1;
+        for (int i = 0; i < exponent_; ++i) {
+            for (int j = 0; j < kHexCharsPerBigit; ++j) {
+                buffer.setCharAt(string_index--, '0');
+            }
+        }
+        for (int i = 0; i < used_digits_ - 1; ++i) {
+            int current_bigit = bigits_[i];
+            for (int j = 0; j < kHexCharsPerBigit; ++j) {
+                buffer.setCharAt(string_index--, hexCharOfValue(current_bigit & 0xF));
+                current_bigit >>>= 4;
+            }
+        }
+        // And finally the last bigit.
+        int most_significant_bigit = bigits_[used_digits_ - 1];
+        while (most_significant_bigit != 0) {
+            buffer.setCharAt(string_index--, hexCharOfValue(most_significant_bigit & 0xF));
+            most_significant_bigit >>>= 4;
+        }
+        return buffer.toString();
+    }
+
+
+    int bigitAt(final int index) {
+        if (index >= bigitLength()) return 0;
+        if (index < exponent_) return 0;
+        return bigits_[index - exponent_];
+    }
+
+
+    static int compare(final Bignum a, final Bignum b) {
+        assert (a.isClamped());
+        assert (b.isClamped());
+        final int bigit_length_a = a.bigitLength();
+        final int bigit_length_b = b.bigitLength();
+        if (bigit_length_a < bigit_length_b) return -1;
+        if (bigit_length_a > bigit_length_b) return +1;
+        for (int i = bigit_length_a - 1; i >= Math.min(a.exponent_, b.exponent_); --i) {
+            final int bigit_a = a.bigitAt(i);
+            final int bigit_b = b.bigitAt(i);
+            if (bigit_a < bigit_b) return -1;
+            if (bigit_a > bigit_b) return +1;
+            // Otherwise they are equal up to this digit. Try the next digit.
+        }
+        return 0;
+    }
+
+
+    static int plusCompare(final Bignum a, final Bignum b, final Bignum c) {
+        assert (a.isClamped());
+        assert (b.isClamped());
+        assert (c.isClamped());
+        if (a.bigitLength() < b.bigitLength()) {
+            return plusCompare(b, a, c);
+        }
+        if (a.bigitLength() + 1 < c.bigitLength()) return -1;
+        if (a.bigitLength() > c.bigitLength()) return +1;
+        // The exponent encodes 0-bigits. So if there are more 0-digits in 'a' than
+        // 'b' has digits, then the bigit-length of 'a'+'b' must be equal to the one
+        // of 'a'.
+        if (a.exponent_ >= b.bigitLength() && a.bigitLength() < c.bigitLength()) {
+            return -1;
+        }
+
+        int borrow = 0;
+        // Starting at min_exponent all digits are == 0. So no need to compare them.
+        final int min_exponent = Math.min(Math.min(a.exponent_, b.exponent_), c.exponent_);
+        for (int i = c.bigitLength() - 1; i >= min_exponent; --i) {
+            final int int_a = a.bigitAt(i);
+            final int int_b = b.bigitAt(i);
+            final int int_c = c.bigitAt(i);
+            final int sum = int_a + int_b;
+            if (sum > int_c + borrow) {
+                return +1;
+            } else {
+                borrow = int_c + borrow - sum;
+                if (borrow > 1) return -1;
+                borrow <<= kBigitSize;
+            }
+        }
+        if (borrow == 0) return 0;
+        return -1;
+    }
+
+
+    void clamp() {
+        while (used_digits_ > 0 && bigits_[used_digits_ - 1] == 0) {
+            used_digits_--;
+        }
+        if (used_digits_ == 0) {
+            // Zero.
+            exponent_ = 0;
+        }
+    }
+
+
+    boolean isClamped() {
+        return used_digits_ == 0 || bigits_[used_digits_ - 1] != 0;
+    }
+
+
+    void zero() {
+        for (int i = 0; i < used_digits_; ++i) {
+            bigits_[i] = 0;
+        }
+        used_digits_ = 0;
+        exponent_ = 0;
+    }
+
+
+    void align(final Bignum other) {
+        if (exponent_ > other.exponent_) {
+            // If "X" represents a "hidden" digit (by the exponent) then we are in the
+            // following case (a == this, b == other):
+            // a:  aaaaaaXXXX   or a:   aaaaaXXX
+            // b:     bbbbbbX      b: bbbbbbbbXX
+            // We replace some of the hidden digits (X) of a with 0 digits.
+            // a:  aaaaaa000X   or a:   aaaaa0XX
+            final int zero_digits = exponent_ - other.exponent_;
+            ensureCapacity(used_digits_ + zero_digits);
+            for (int i = used_digits_ - 1; i >= 0; --i) {
+                bigits_[i + zero_digits] = bigits_[i];
+            }
+            for (int i = 0; i < zero_digits; ++i) {
+                bigits_[i] = 0;
+            }
+            used_digits_ += zero_digits;
+            exponent_ -= zero_digits;
+            assert (used_digits_ >= 0);
+            assert (exponent_ >= 0);
+        }
+    }
+
+
+    void bigitsShiftLeft(final int shift_amount) {
+        assert (shift_amount < kBigitSize);
+        assert (shift_amount >= 0);
+        int carry = 0;
+        for (int i = 0; i < used_digits_; ++i) {
+            final int new_carry = bigits_[i] >>> (kBigitSize - shift_amount);
+            bigits_[i] = ((bigits_[i] << shift_amount) + carry) & kBigitMask;
+            carry = new_carry;
+        }
+        if (carry != 0) {
+            bigits_[used_digits_] = carry;
+            used_digits_++;
+        }
+    }
+
+
+    void subtractTimes(final Bignum other, final int factor) {
+        assert (exponent_ <= other.exponent_);
+        if (factor < 3) {
+            for (int i = 0; i < factor; ++i) {
+                subtractBignum(other);
+            }
+            return;
+        }
+        int borrow = 0;
+        final int exponent_diff = other.exponent_ - exponent_;
+        for (int i = 0; i < other.used_digits_; ++i) {
+            final long product = ((long) factor) * other.bigits_[i];
+            final long remove = borrow + product;
+            final int difference = bigits_[i + exponent_diff] - (int) (remove & kBigitMask);
+            bigits_[i + exponent_diff] = difference & kBigitMask;
+            borrow = (int) ((difference >>> (kChunkSize - 1)) +
+                    (remove >>> kBigitSize));
+        }
+        for (int i = other.used_digits_ + exponent_diff; i < used_digits_; ++i) {
+            if (borrow == 0) return;
+            final int difference = bigits_[i] - borrow;
+            bigits_[i] = difference & kBigitMask;
+            borrow = difference >>> (kChunkSize - 1);
+        }
+        clamp();
+    }
+
+    @Override
+    public String toString() {
+        return "Bignum" + Arrays.toString(bigits_);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/doubleconv/BignumDtoa.java	Wed Nov 11 15:22:14 2015 +0100
@@ -0,0 +1,647 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// This file is available under and governed by the GNU General Public
+// License version 2 only, as published by the Free Software Foundation.
+// However, the following notice accompanied the original version of this
+// file:
+//
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package jdk.nashorn.internal.runtime.doubleconv;
+
+// Dtoa implementation based on our own Bignum implementation, supporting
+// all conversion modes but slightly slower than the specialized implementations.
+class BignumDtoa {
+
+    private static int normalizedExponent(long significand, int exponent) {
+        assert (significand != 0);
+        while ((significand & IeeeDouble.kHiddenBit) == 0) {
+            significand = significand << 1;
+            exponent = exponent - 1;
+        }
+        return exponent;
+    }
+
+    // Converts the given double 'v' to ascii.
+    // The result should be interpreted as buffer * 10^(point-length).
+    // The buffer will be null-terminated.
+    //
+    // The input v must be > 0 and different from NaN, and Infinity.
+    //
+    // The output depends on the given mode:
+    //  - SHORTEST: produce the least amount of digits for which the internal
+    //   identity requirement is still satisfied. If the digits are printed
+    //   (together with the correct exponent) then reading this number will give
+    //   'v' again. The buffer will choose the representation that is closest to
+    //   'v'. If there are two at the same distance, than the number is round up.
+    //   In this mode the 'requested_digits' parameter is ignored.
+    //  - FIXED: produces digits necessary to print a given number with
+    //   'requested_digits' digits after the decimal point. The produced digits
+    //   might be too short in which case the caller has to fill the gaps with '0's.
+    //   Example: toFixed(0.001, 5) is allowed to return buffer="1", point=-2.
+    //   Halfway cases are rounded up. The call toFixed(0.15, 2) thus returns
+    //     buffer="2", point=0.
+    //   Note: the length of the returned buffer has no meaning wrt the significance
+    //   of its digits. That is, just because it contains '0's does not mean that
+    //   any other digit would not satisfy the internal identity requirement.
+    //  - PRECISION: produces 'requested_digits' where the first digit is not '0'.
+    //   Even though the length of produced digits usually equals
+    //   'requested_digits', the function is allowed to return fewer digits, in
+    //   which case the caller has to fill the missing digits with '0's.
+    //   Halfway cases are again rounded up.
+    // 'BignumDtoa' expects the given buffer to be big enough to hold all digits
+    // and a terminating null-character.
+    static void bignumDtoa(final double v, final DtoaMode mode, final int requested_digits,
+                    final DtoaBuffer buffer) {
+        assert (v > 0);
+        assert (!IeeeDouble.isSpecial(IeeeDouble.doubleToLong(v)));
+        final long significand;
+        final int exponent;
+        final boolean lower_boundary_is_closer;
+
+        final long l = IeeeDouble.doubleToLong(v);
+        significand = IeeeDouble.significand(l);
+        exponent = IeeeDouble.exponent(l);
+        lower_boundary_is_closer = IeeeDouble.lowerBoundaryIsCloser(l);
+
+        final boolean need_boundary_deltas = mode == DtoaMode.SHORTEST;
+
+        final boolean is_even = (significand & 1) == 0;
+        assert (significand != 0);
+        final int normalizedExponent = normalizedExponent(significand, exponent);
+        // estimated_power might be too low by 1.
+        final int estimated_power = estimatePower(normalizedExponent);
+
+        // Shortcut for Fixed.
+        // The requested digits correspond to the digits after the point. If the
+        // number is much too small, then there is no need in trying to get any
+        // digits.
+        if (mode == DtoaMode.FIXED && -estimated_power - 1 > requested_digits) {
+            buffer.reset();
+            // Set decimal-point to -requested_digits. This is what Gay does.
+            // Note that it should not have any effect anyways since the string is
+            // empty.
+            buffer.decimalPoint = -requested_digits;
+            return;
+        }
+
+        final Bignum numerator = new Bignum();
+        final Bignum denominator = new Bignum();
+        final Bignum delta_minus = new Bignum();
+        final Bignum delta_plus = new Bignum();
+        // Make sure the bignum can grow large enough. The smallest double equals
+        // 4e-324. In this case the denominator needs fewer than 324*4 binary digits.
+        // The maximum double is 1.7976931348623157e308 which needs fewer than
+        // 308*4 binary digits.
+        assert (Bignum.kMaxSignificantBits >= 324*4);
+        initialScaledStartValues(significand, exponent, lower_boundary_is_closer,
+                estimated_power, need_boundary_deltas,
+                numerator, denominator,
+                delta_minus, delta_plus);
+        // We now have v = (numerator / denominator) * 10^estimated_power.
+        buffer.decimalPoint = fixupMultiply10(estimated_power, is_even,
+                numerator, denominator,
+                delta_minus, delta_plus);
+        // We now have v = (numerator / denominator) * 10^(decimal_point-1), and
+        //  1 <= (numerator + delta_plus) / denominator < 10
+        switch (mode) {
+            case SHORTEST:
+                generateShortestDigits(numerator, denominator,
+                        delta_minus, delta_plus,
+                        is_even, buffer);
+                break;
+            case FIXED:
+                bignumToFixed(requested_digits,
+                        numerator, denominator,
+                        buffer);
+                break;
+            case PRECISION:
+                generateCountedDigits(requested_digits,
+                        numerator, denominator,
+                        buffer);
+                break;
+            default:
+                throw new RuntimeException();
+        }
+    }
+
+
+    // The procedure starts generating digits from the left to the right and stops
+    // when the generated digits yield the shortest decimal representation of v. A
+    // decimal representation of v is a number lying closer to v than to any other
+    // double, so it converts to v when read.
+    //
+    // This is true if d, the decimal representation, is between m- and m+, the
+    // upper and lower boundaries. d must be strictly between them if !is_even.
+    //           m- := (numerator - delta_minus) / denominator
+    //           m+ := (numerator + delta_plus) / denominator
+    //
+    // Precondition: 0 <= (numerator+delta_plus) / denominator < 10.
+    //   If 1 <= (numerator+delta_plus) / denominator < 10 then no leading 0 digit
+    //   will be produced. This should be the standard precondition.
+    static void generateShortestDigits(final Bignum numerator, final Bignum denominator,
+                                       final Bignum delta_minus, Bignum delta_plus,
+                                       final boolean is_even,
+                                       final DtoaBuffer buffer) {
+        // Small optimization: if delta_minus and delta_plus are the same just reuse
+        // one of the two bignums.
+        if (Bignum.equal(delta_minus, delta_plus)) {
+            delta_plus = delta_minus;
+        }
+        for (;;) {
+            final char digit;
+            digit = numerator.divideModuloIntBignum(denominator);
+            assert (digit <= 9);  // digit is a uint16_t and therefore always positive.
+            // digit = numerator / denominator (integer division).
+            // numerator = numerator % denominator.
+            buffer.append((char) (digit + '0'));
+
+            // Can we stop already?
+            // If the remainder of the division is less than the distance to the lower
+            // boundary we can stop. In this case we simply round down (discarding the
+            // remainder).
+            // Similarly we test if we can round up (using the upper boundary).
+            final boolean in_delta_room_minus;
+            final boolean in_delta_room_plus;
+            if (is_even) {
+                in_delta_room_minus = Bignum.lessEqual(numerator, delta_minus);
+            } else {
+                in_delta_room_minus = Bignum.less(numerator, delta_minus);
+            }
+            if (is_even) {
+                in_delta_room_plus =
+                        Bignum.plusCompare(numerator, delta_plus, denominator) >= 0;
+            } else {
+                in_delta_room_plus =
+                        Bignum.plusCompare(numerator, delta_plus, denominator) > 0;
+            }
+            if (!in_delta_room_minus && !in_delta_room_plus) {
+                // Prepare for next iteration.
+                numerator.times10();
+                delta_minus.times10();
+                // We optimized delta_plus to be equal to delta_minus (if they share the
+                // same value). So don't multiply delta_plus if they point to the same
+                // object.
+                if (delta_minus != delta_plus) {
+                    delta_plus.times10();
+                }
+            } else if (in_delta_room_minus && in_delta_room_plus) {
+                // Let's see if 2*numerator < denominator.
+                // If yes, then the next digit would be < 5 and we can round down.
+                final int compare = Bignum.plusCompare(numerator, numerator, denominator);
+                if (compare < 0) {
+                    // Remaining digits are less than .5. -> Round down (== do nothing).
+                } else if (compare > 0) {
+                    // Remaining digits are more than .5 of denominator. -> Round up.
+                    // Note that the last digit could not be a '9' as otherwise the whole
+                    // loop would have stopped earlier.
+                    // We still have an assert here in case the preconditions were not
+                    // satisfied.
+                    assert (buffer.chars[buffer.length - 1] != '9');
+                    buffer.chars[buffer.length - 1]++;
+                } else {
+                    // Halfway case.
+                    // TODO(floitsch): need a way to solve half-way cases.
+                    //   For now let's round towards even (since this is what Gay seems to
+                    //   do).
+
+                    if ((buffer.chars[buffer.length - 1] - '0') % 2 == 0) {
+                        // Round down => Do nothing.
+                    } else {
+                        assert (buffer.chars[buffer.length - 1] != '9');
+                        buffer.chars[buffer.length - 1]++;
+                    }
+                }
+                return;
+            } else if (in_delta_room_minus) {
+                // Round down (== do nothing).
+                return;
+            } else {  // in_delta_room_plus
+                // Round up.
+                // Note again that the last digit could not be '9' since this would have
+                // stopped the loop earlier.
+                // We still have an ASSERT here, in case the preconditions were not
+                // satisfied.
+                assert (buffer.chars[buffer.length -1] != '9');
+                buffer.chars[buffer.length - 1]++;
+                return;
+            }
+        }
+    }
+
+
+    // Let v = numerator / denominator < 10.
+    // Then we generate 'count' digits of d = x.xxxxx... (without the decimal point)
+    // from left to right. Once 'count' digits have been produced we decide wether
+    // to round up or down. Remainders of exactly .5 round upwards. Numbers such
+    // as 9.999999 propagate a carry all the way, and change the
+    // exponent (decimal_point), when rounding upwards.
+    static void generateCountedDigits(final int count,
+                                      final Bignum numerator, final Bignum denominator,
+                                      final DtoaBuffer buffer) {
+        assert (count >= 0);
+        for (int i = 0; i < count - 1; ++i) {
+            final char digit;
+            digit = numerator.divideModuloIntBignum(denominator);
+            assert (digit <= 9);  // digit is a uint16_t and therefore always positive.
+            // digit = numerator / denominator (integer division).
+            // numerator = numerator % denominator.
+            buffer.chars[i] = (char)(digit + '0');
+            // Prepare for next iteration.
+            numerator.times10();
+        }
+        // Generate the last digit.
+        char digit;
+        digit = numerator.divideModuloIntBignum(denominator);
+        if (Bignum.plusCompare(numerator, numerator, denominator) >= 0) {
+            digit++;
+        }
+        assert (digit <= 10);
+        buffer.chars[count - 1] = (char) (digit + '0');
+        // Correct bad digits (in case we had a sequence of '9's). Propagate the
+        // carry until we hat a non-'9' or til we reach the first digit.
+        for (int i = count - 1; i > 0; --i) {
+            if (buffer.chars[i] != '0' + 10) break;
+            buffer.chars[i] = '0';
+            buffer.chars[i - 1]++;
+        }
+        if (buffer.chars[0] == '0' + 10) {
+            // Propagate a carry past the top place.
+            buffer.chars[0] = '1';
+            buffer.decimalPoint++;
+        }
+        buffer.length = count;
+    }
+
+
+    // Generates 'requested_digits' after the decimal point. It might omit
+    // trailing '0's. If the input number is too small then no digits at all are
+    // generated (ex.: 2 fixed digits for 0.00001).
+    //
+    // Input verifies:  1 <= (numerator + delta) / denominator < 10.
+    static void bignumToFixed(final int requested_digits,
+                              final Bignum numerator, final Bignum denominator,
+                              final DtoaBuffer buffer) {
+        // Note that we have to look at more than just the requested_digits, since
+        // a number could be rounded up. Example: v=0.5 with requested_digits=0.
+        // Even though the power of v equals 0 we can't just stop here.
+        if (-buffer.decimalPoint > requested_digits) {
+            // The number is definitively too small.
+            // Ex: 0.001 with requested_digits == 1.
+            // Set decimal-decimalPoint to -requested_digits. This is what Gay does.
+            // Note that it should not have any effect anyways since the string is
+            // empty.
+            buffer.decimalPoint = -requested_digits;
+            buffer.length = 0;
+            // return;
+        } else if (-buffer.decimalPoint == requested_digits) {
+            // We only need to verify if the number rounds down or up.
+            // Ex: 0.04 and 0.06 with requested_digits == 1.
+            assert (buffer.decimalPoint == -requested_digits);
+            // Initially the fraction lies in range (1, 10]. Multiply the denominator
+            // by 10 so that we can compare more easily.
+            denominator.times10();
+            if (Bignum.plusCompare(numerator, numerator, denominator) >= 0) {
+                // If the fraction is >= 0.5 then we have to include the rounded
+                // digit.
+                buffer.chars[0] = '1';
+                buffer.length = 1;
+                buffer.decimalPoint++;
+            } else {
+                // Note that we caught most of similar cases earlier.
+                buffer.length = 0;
+            }
+            // return;
+        } else {
+            // The requested digits correspond to the digits after the point.
+            // The variable 'needed_digits' includes the digits before the point.
+            final int needed_digits = buffer.decimalPoint + requested_digits;
+            generateCountedDigits(needed_digits,
+                    numerator, denominator,
+                    buffer);
+        }
+    }
+
+
+    // Returns an estimation of k such that 10^(k-1) <= v < 10^k where
+    // v = f * 2^exponent and 2^52 <= f < 2^53.
+    // v is hence a normalized double with the given exponent. The output is an
+    // approximation for the exponent of the decimal approimation .digits * 10^k.
+    //
+    // The result might undershoot by 1 in which case 10^k <= v < 10^k+1.
+    // Note: this property holds for v's upper boundary m+ too.
+    //    10^k <= m+ < 10^k+1.
+    //   (see explanation below).
+    //
+    // Examples:
+    //  EstimatePower(0)   => 16
+    //  EstimatePower(-52) => 0
+    //
+    // Note: e >= 0 => EstimatedPower(e) > 0. No similar claim can be made for e<0.
+    static int estimatePower(final int exponent) {
+        // This function estimates log10 of v where v = f*2^e (with e == exponent).
+        // Note that 10^floor(log10(v)) <= v, but v <= 10^ceil(log10(v)).
+        // Note that f is bounded by its container size. Let p = 53 (the double's
+        // significand size). Then 2^(p-1) <= f < 2^p.
+        //
+        // Given that log10(v) == log2(v)/log2(10) and e+(len(f)-1) is quite close
+        // to log2(v) the function is simplified to (e+(len(f)-1)/log2(10)).
+        // The computed number undershoots by less than 0.631 (when we compute log3
+        // and not log10).
+        //
+        // Optimization: since we only need an approximated result this computation
+        // can be performed on 64 bit integers. On x86/x64 architecture the speedup is
+        // not really measurable, though.
+        //
+        // Since we want to avoid overshooting we decrement by 1e10 so that
+        // floating-point imprecisions don't affect us.
+        //
+        // Explanation for v's boundary m+: the computation takes advantage of
+        // the fact that 2^(p-1) <= f < 2^p. Boundaries still satisfy this requirement
+        // (even for denormals where the delta can be much more important).
+
+        final double k1Log10 = 0.30102999566398114;  // 1/lg(10)
+
+        // For doubles len(f) == 53 (don't forget the hidden bit).
+        final int kSignificandSize = IeeeDouble.kSignificandSize;
+        final double estimate = Math.ceil((exponent + kSignificandSize - 1) * k1Log10 - 1e-10);
+        return (int) estimate;
+    }
+
+
+    // See comments for InitialScaledStartValues.
+    static void initialScaledStartValuesPositiveExponent(
+            final long significand, final int exponent,
+            final int estimated_power, final boolean need_boundary_deltas,
+            final Bignum numerator, final Bignum denominator,
+            final Bignum delta_minus, final Bignum delta_plus) {
+        // A positive exponent implies a positive power.
+        assert (estimated_power >= 0);
+        // Since the estimated_power is positive we simply multiply the denominator
+        // by 10^estimated_power.
+
+        // numerator = v.
+        numerator.assignUInt64(significand);
+        numerator.shiftLeft(exponent);
+        // denominator = 10^estimated_power.
+        denominator.assignPowerUInt16(10, estimated_power);
+
+        if (need_boundary_deltas) {
+            // Introduce a common denominator so that the deltas to the boundaries are
+            // integers.
+            denominator.shiftLeft(1);
+            numerator.shiftLeft(1);
+            // Let v = f * 2^e, then m+ - v = 1/2 * 2^e; With the common
+            // denominator (of 2) delta_plus equals 2^e.
+            delta_plus.assignUInt16((char) 1);
+            delta_plus.shiftLeft(exponent);
+            // Same for delta_minus. The adjustments if f == 2^p-1 are done later.
+            delta_minus.assignUInt16((char) 1);
+            delta_minus.shiftLeft(exponent);
+        }
+    }
+
+
+    // See comments for InitialScaledStartValues
+    static void initialScaledStartValuesNegativeExponentPositivePower(
+            final long significand, final int exponent,
+            final int estimated_power, final boolean need_boundary_deltas,
+            final Bignum numerator, final Bignum denominator,
+            final Bignum delta_minus, final Bignum delta_plus) {
+        // v = f * 2^e with e < 0, and with estimated_power >= 0.
+        // This means that e is close to 0 (have a look at how estimated_power is
+        // computed).
+
+        // numerator = significand
+        //  since v = significand * 2^exponent this is equivalent to
+        //  numerator = v * / 2^-exponent
+        numerator.assignUInt64(significand);
+        // denominator = 10^estimated_power * 2^-exponent (with exponent < 0)
+        denominator.assignPowerUInt16(10, estimated_power);
+        denominator.shiftLeft(-exponent);
+
+        if (need_boundary_deltas) {
+            // Introduce a common denominator so that the deltas to the boundaries are
+            // integers.
+            denominator.shiftLeft(1);
+            numerator.shiftLeft(1);
+            // Let v = f * 2^e, then m+ - v = 1/2 * 2^e; With the common
+            // denominator (of 2) delta_plus equals 2^e.
+            // Given that the denominator already includes v's exponent the distance
+            // to the boundaries is simply 1.
+            delta_plus.assignUInt16((char) 1);
+            // Same for delta_minus. The adjustments if f == 2^p-1 are done later.
+            delta_minus.assignUInt16((char) 1);
+        }
+    }
+
+
+    // See comments for InitialScaledStartValues
+    static void initialScaledStartValuesNegativeExponentNegativePower(
+            final long significand, final int exponent,
+            final int estimated_power, final boolean need_boundary_deltas,
+            final Bignum numerator, final Bignum denominator,
+            final Bignum delta_minus, final Bignum delta_plus) {
+        // Instead of multiplying the denominator with 10^estimated_power we
+        // multiply all values (numerator and deltas) by 10^-estimated_power.
+
+        // Use numerator as temporary container for power_ten.
+        final Bignum power_ten = numerator;
+        power_ten.assignPowerUInt16(10, -estimated_power);
+
+        if (need_boundary_deltas) {
+            // Since power_ten == numerator we must make a copy of 10^estimated_power
+            // before we complete the computation of the numerator.
+            // delta_plus = delta_minus = 10^estimated_power
+            delta_plus.assignBignum(power_ten);
+            delta_minus.assignBignum(power_ten);
+        }
+
+        // numerator = significand * 2 * 10^-estimated_power
+        //  since v = significand * 2^exponent this is equivalent to
+        // numerator = v * 10^-estimated_power * 2 * 2^-exponent.
+        // Remember: numerator has been abused as power_ten. So no need to assign it
+        //  to itself.
+        assert (numerator == power_ten);
+        numerator.multiplyByUInt64(significand);
+
+        // denominator = 2 * 2^-exponent with exponent < 0.
+        denominator.assignUInt16((char) 1);
+        denominator.shiftLeft(-exponent);
+
+        if (need_boundary_deltas) {
+            // Introduce a common denominator so that the deltas to the boundaries are
+            // integers.
+            numerator.shiftLeft(1);
+            denominator.shiftLeft(1);
+            // With this shift the boundaries have their correct value, since
+            // delta_plus = 10^-estimated_power, and
+            // delta_minus = 10^-estimated_power.
+            // These assignments have been done earlier.
+            // The adjustments if f == 2^p-1 (lower boundary is closer) are done later.
+        }
+    }
+
+
+    // Let v = significand * 2^exponent.
+    // Computes v / 10^estimated_power exactly, as a ratio of two bignums, numerator
+    // and denominator. The functions GenerateShortestDigits and
+    // GenerateCountedDigits will then convert this ratio to its decimal
+    // representation d, with the required accuracy.
+    // Then d * 10^estimated_power is the representation of v.
+    // (Note: the fraction and the estimated_power might get adjusted before
+    // generating the decimal representation.)
+    //
+    // The initial start values consist of:
+    //  - a scaled numerator: s.t. numerator/denominator == v / 10^estimated_power.
+    //  - a scaled (common) denominator.
+    //  optionally (used by GenerateShortestDigits to decide if it has the shortest
+    //  decimal converting back to v):
+    //  - v - m-: the distance to the lower boundary.
+    //  - m+ - v: the distance to the upper boundary.
+    //
+    // v, m+, m-, and therefore v - m- and m+ - v all share the same denominator.
+    //
+    // Let ep == estimated_power, then the returned values will satisfy:
+    //  v / 10^ep = numerator / denominator.
+    //  v's boundarys m- and m+:
+    //    m- / 10^ep == v / 10^ep - delta_minus / denominator
+    //    m+ / 10^ep == v / 10^ep + delta_plus / denominator
+    //  Or in other words:
+    //    m- == v - delta_minus * 10^ep / denominator;
+    //    m+ == v + delta_plus * 10^ep / denominator;
+    //
+    // Since 10^(k-1) <= v < 10^k    (with k == estimated_power)
+    //  or       10^k <= v < 10^(k+1)
+    //  we then have 0.1 <= numerator/denominator < 1
+    //           or    1 <= numerator/denominator < 10
+    //
+    // It is then easy to kickstart the digit-generation routine.
+    //
+    // The boundary-deltas are only filled if the mode equals BIGNUM_DTOA_SHORTEST
+    // or BIGNUM_DTOA_SHORTEST_SINGLE.
+
+    static void initialScaledStartValues(final long significand,
+                                         final int exponent,
+                                         final boolean lower_boundary_is_closer,
+                                         final int estimated_power,
+                                         final boolean need_boundary_deltas,
+                                         final Bignum numerator,
+                                         final Bignum denominator,
+                                         final Bignum delta_minus,
+                                         final Bignum delta_plus) {
+        if (exponent >= 0) {
+            initialScaledStartValuesPositiveExponent(
+                    significand, exponent, estimated_power, need_boundary_deltas,
+                    numerator, denominator, delta_minus, delta_plus);
+        } else if (estimated_power >= 0) {
+            initialScaledStartValuesNegativeExponentPositivePower(
+                    significand, exponent, estimated_power, need_boundary_deltas,
+                    numerator, denominator, delta_minus, delta_plus);
+        } else {
+            initialScaledStartValuesNegativeExponentNegativePower(
+                    significand, exponent, estimated_power, need_boundary_deltas,
+                    numerator, denominator, delta_minus, delta_plus);
+        }
+
+        if (need_boundary_deltas && lower_boundary_is_closer) {
+            // The lower boundary is closer at half the distance of "normal" numbers.
+            // Increase the common denominator and adapt all but the delta_minus.
+            denominator.shiftLeft(1);  // *2
+            numerator.shiftLeft(1);    // *2
+            delta_plus.shiftLeft(1);   // *2
+        }
+    }
+
+
+    // This routine multiplies numerator/denominator so that its values lies in the
+    // range 1-10. That is after a call to this function we have:
+    //    1 <= (numerator + delta_plus) /denominator < 10.
+    // Let numerator the input before modification and numerator' the argument
+    // after modification, then the output-parameter decimal_point is such that
+    //  numerator / denominator * 10^estimated_power ==
+    //    numerator' / denominator' * 10^(decimal_point - 1)
+    // In some cases estimated_power was too low, and this is already the case. We
+    // then simply adjust the power so that 10^(k-1) <= v < 10^k (with k ==
+    // estimated_power) but do not touch the numerator or denominator.
+    // Otherwise the routine multiplies the numerator and the deltas by 10.
+    static int fixupMultiply10(final int estimated_power, final boolean is_even,
+                                final Bignum numerator, final Bignum denominator,
+                                final Bignum delta_minus, final Bignum delta_plus) {
+        final boolean in_range;
+        final int decimal_point;
+        if (is_even) {
+            // For IEEE doubles half-way cases (in decimal system numbers ending with 5)
+            // are rounded to the closest floating-point number with even significand.
+            in_range = Bignum.plusCompare(numerator, delta_plus, denominator) >= 0;
+        } else {
+            in_range = Bignum.plusCompare(numerator, delta_plus, denominator) > 0;
+        }
+        if (in_range) {
+            // Since numerator + delta_plus >= denominator we already have
+            // 1 <= numerator/denominator < 10. Simply update the estimated_power.
+            decimal_point = estimated_power + 1;
+        } else {
+            decimal_point = estimated_power;
+            numerator.times10();
+            if (Bignum.equal(delta_minus, delta_plus)) {
+                delta_minus.times10();
+                delta_plus.assignBignum(delta_minus);
+            } else {
+                delta_minus.times10();
+                delta_plus.times10();
+            }
+        }
+        return decimal_point;
+    }
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/doubleconv/CachedPowers.java	Wed Nov 11 15:22:14 2015 +0100
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// This file is available under and governed by the GNU General Public
+// License version 2 only, as published by the Free Software Foundation.
+// However, the following notice accompanied the original version of this
+// file:
+//
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package jdk.nashorn.internal.runtime.doubleconv;
+
+public class CachedPowers {
+
+    static class CachedPower {
+        final private long significand;
+        final private int binaryExponent;
+        final private int decimalExponent;
+
+        CachedPower(final long significand, final int binaryExponent, final int decimalExponent) {
+            this.significand = significand;
+            this.binaryExponent = binaryExponent;
+            this.decimalExponent = decimalExponent;
+        }
+    }
+
+    static private final CachedPower[] kCachedPowers = {
+            new CachedPower(0xfa8fd5a0081c0288L, -1220, -348),
+            new CachedPower(0xbaaee17fa23ebf76L, -1193, -340),
+            new CachedPower(0x8b16fb203055ac76L, -1166, -332),
+            new CachedPower(0xcf42894a5dce35eaL, -1140, -324),
+            new CachedPower(0x9a6bb0aa55653b2dL, -1113, -316),
+            new CachedPower(0xe61acf033d1a45dfL, -1087, -308),
+            new CachedPower(0xab70fe17c79ac6caL, -1060, -300),
+            new CachedPower(0xff77b1fcbebcdc4fL, -1034, -292),
+            new CachedPower(0xbe5691ef416bd60cL, -1007, -284),
+            new CachedPower(0x8dd01fad907ffc3cL, -980, -276),
+            new CachedPower(0xd3515c2831559a83L, -954, -268),
+            new CachedPower(0x9d71ac8fada6c9b5L, -927, -260),
+            new CachedPower(0xea9c227723ee8bcbL, -901, -252),
+            new CachedPower(0xaecc49914078536dL, -874, -244),
+            new CachedPower(0x823c12795db6ce57L, -847, -236),
+            new CachedPower(0xc21094364dfb5637L, -821, -228),
+            new CachedPower(0x9096ea6f3848984fL, -794, -220),
+            new CachedPower(0xd77485cb25823ac7L, -768, -212),
+            new CachedPower(0xa086cfcd97bf97f4L, -741, -204),
+            new CachedPower(0xef340a98172aace5L, -715, -196),
+            new CachedPower(0xb23867fb2a35b28eL, -688, -188),
+            new CachedPower(0x84c8d4dfd2c63f3bL, -661, -180),
+            new CachedPower(0xc5dd44271ad3cdbaL, -635, -172),
+            new CachedPower(0x936b9fcebb25c996L, -608, -164),
+            new CachedPower(0xdbac6c247d62a584L, -582, -156),
+            new CachedPower(0xa3ab66580d5fdaf6L, -555, -148),
+            new CachedPower(0xf3e2f893dec3f126L, -529, -140),
+            new CachedPower(0xb5b5ada8aaff80b8L, -502, -132),
+            new CachedPower(0x87625f056c7c4a8bL, -475, -124),
+            new CachedPower(0xc9bcff6034c13053L, -449, -116),
+            new CachedPower(0x964e858c91ba2655L, -422, -108),
+            new CachedPower(0xdff9772470297ebdL, -396, -100),
+            new CachedPower(0xa6dfbd9fb8e5b88fL, -369, -92),
+            new CachedPower(0xf8a95fcf88747d94L, -343, -84),
+            new CachedPower(0xb94470938fa89bcfL, -316, -76),
+            new CachedPower(0x8a08f0f8bf0f156bL, -289, -68),
+            new CachedPower(0xcdb02555653131b6L, -263, -60),
+            new CachedPower(0x993fe2c6d07b7facL, -236, -52),
+            new CachedPower(0xe45c10c42a2b3b06L, -210, -44),
+            new CachedPower(0xaa242499697392d3L, -183, -36),
+            new CachedPower(0xfd87b5f28300ca0eL, -157, -28),
+            new CachedPower(0xbce5086492111aebL, -130, -20),
+            new CachedPower(0x8cbccc096f5088ccL, -103, -12),
+            new CachedPower(0xd1b71758e219652cL, -77, -4),
+            new CachedPower(0x9c40000000000000L, -50, 4),
+            new CachedPower(0xe8d4a51000000000L, -24, 12),
+            new CachedPower(0xad78ebc5ac620000L, 3, 20),
+            new CachedPower(0x813f3978f8940984L, 30, 28),
+            new CachedPower(0xc097ce7bc90715b3L, 56, 36),
+            new CachedPower(0x8f7e32ce7bea5c70L, 83, 44),
+            new CachedPower(0xd5d238a4abe98068L, 109, 52),
+            new CachedPower(0x9f4f2726179a2245L, 136, 60),
+            new CachedPower(0xed63a231d4c4fb27L, 162, 68),
+            new CachedPower(0xb0de65388cc8ada8L, 189, 76),
+            new CachedPower(0x83c7088e1aab65dbL, 216, 84),
+            new CachedPower(0xc45d1df942711d9aL, 242, 92),
+            new CachedPower(0x924d692ca61be758L, 269, 100),
+            new CachedPower(0xda01ee641a708deaL, 295, 108),
+            new CachedPower(0xa26da3999aef774aL, 322, 116),
+            new CachedPower(0xf209787bb47d6b85L, 348, 124),
+            new CachedPower(0xb454e4a179dd1877L, 375, 132),
+            new CachedPower(0x865b86925b9bc5c2L, 402, 140),
+            new CachedPower(0xc83553c5c8965d3dL, 428, 148),
+            new CachedPower(0x952ab45cfa97a0b3L, 455, 156),
+            new CachedPower(0xde469fbd99a05fe3L, 481, 164),
+            new CachedPower(0xa59bc234db398c25L, 508, 172),
+            new CachedPower(0xf6c69a72a3989f5cL, 534, 180),
+            new CachedPower(0xb7dcbf5354e9beceL, 561, 188),
+            new CachedPower(0x88fcf317f22241e2L, 588, 196),
+            new CachedPower(0xcc20ce9bd35c78a5L, 614, 204),
+            new CachedPower(0x98165af37b2153dfL, 641, 212),
+            new CachedPower(0xe2a0b5dc971f303aL, 667, 220),
+            new CachedPower(0xa8d9d1535ce3b396L, 694, 228),
+            new CachedPower(0xfb9b7cd9a4a7443cL, 720, 236),
+            new CachedPower(0xbb764c4ca7a44410L, 747, 244),
+            new CachedPower(0x8bab8eefb6409c1aL, 774, 252),
+            new CachedPower(0xd01fef10a657842cL, 800, 260),
+            new CachedPower(0x9b10a4e5e9913129L, 827, 268),
+            new CachedPower(0xe7109bfba19c0c9dL, 853, 276),
+            new CachedPower(0xac2820d9623bf429L, 880, 284),
+            new CachedPower(0x80444b5e7aa7cf85L, 907, 292),
+            new CachedPower(0xbf21e44003acdd2dL, 933, 300),
+            new CachedPower(0x8e679c2f5e44ff8fL, 960, 308),
+            new CachedPower(0xd433179d9c8cb841L, 986, 316),
+            new CachedPower(0x9e19db92b4e31ba9L, 1013, 324),
+            new CachedPower(0xeb96bf6ebadf77d9L, 1039, 332),
+            new CachedPower(0xaf87023b9bf0ee6bL, 1066, 340)
+    };
+
+    static final int kCachedPowersOffset = 348;  // -1 * the first decimal_exponent.
+    static final double kD_1_LOG2_10 = 0.30102999566398114;  //  1 / lg(10)
+    // Difference between the decimal exponents in the table above.
+    static final int kDecimalExponentDistance = 8;
+    static final int kMinDecimalExponent = -348;
+    static final int kMaxDecimalExponent = 340;
+
+    static int getCachedPowerForBinaryExponentRange(
+            final int min_exponent,
+            final int max_exponent,
+            final DiyFp power) {
+        final int kQ = DiyFp.kSignificandSize;
+        final double k = Math.ceil((min_exponent + kQ - 1) * kD_1_LOG2_10);
+        final int index =
+                (kCachedPowersOffset + (int) k - 1) / kDecimalExponentDistance + 1;
+        assert (0 <= index && index < kCachedPowers.length);
+        final CachedPower cached_power = kCachedPowers[index];
+        assert (min_exponent <= cached_power.binaryExponent);
+        assert (cached_power.binaryExponent <= max_exponent);
+        power.setF(cached_power.significand);
+        power.setE(cached_power.binaryExponent);
+        return cached_power.decimalExponent;
+    }
+
+
+    static int getCachedPowerForDecimalExponent(final int requested_exponent,
+                                                final DiyFp power) {
+        assert (kMinDecimalExponent <= requested_exponent);
+        assert (requested_exponent < kMaxDecimalExponent + kDecimalExponentDistance);
+        final int index =
+                (requested_exponent + kCachedPowersOffset) / kDecimalExponentDistance;
+        final CachedPower cached_power = kCachedPowers[index];
+        power.setF(cached_power.significand);
+        power.setE(cached_power.binaryExponent);
+        final int found_exponent = cached_power.decimalExponent;
+        assert (found_exponent <= requested_exponent);
+        assert (requested_exponent < found_exponent + kDecimalExponentDistance);
+        return cached_power.decimalExponent;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/doubleconv/DiyFp.java	Wed Nov 11 15:22:14 2015 +0100
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// This file is available under and governed by the GNU General Public
+// License version 2 only, as published by the Free Software Foundation.
+// However, the following notice accompanied the original version of this
+// file:
+//
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package jdk.nashorn.internal.runtime.doubleconv;
+
+// This "Do It Yourself Floating Point" class implements a floating-point number
+// with a uint64 significand and an int exponent. Normalized DiyFp numbers will
+// have the most significant bit of the significand set.
+// Multiplication and Subtraction do not normalize their results.
+// DiyFp are not designed to contain special doubles (NaN and Infinity).
+class DiyFp {
+
+    private long f_;
+    private int e_;
+
+    static final int kSignificandSize = 64;
+    static final long kUint64MSB = 0x8000000000000000L;
+
+
+    DiyFp() {
+        this.f_ = 0;
+        this.e_ = 0;
+    }
+
+    DiyFp(final long f, final int e) {
+        this.f_ = f;
+        this.e_ = e;
+    }
+
+    // this = this - other.
+    // The exponents of both numbers must be the same and the significand of this
+    // must be bigger than the significand of other.
+    // The result will not be normalized.
+    void subtract(final DiyFp other) {
+        assert (e_ == other.e_);
+        assert Long.compareUnsigned(f_, other.f_) >= 0;
+        f_ -= other.f_;
+    }
+
+    // Returns a - b.
+    // The exponents of both numbers must be the same and this must be bigger
+    // than other. The result will not be normalized.
+    static DiyFp minus(final DiyFp a, final DiyFp b) {
+        final DiyFp result = new DiyFp(a.f_, a.e_);
+        result.subtract(b);
+        return result;
+    }
+
+
+    // this = this * other.
+    final void multiply(final DiyFp other) {
+        // Simply "emulates" a 128 bit multiplication.
+        // However: the resulting number only contains 64 bits. The least
+        // significant 64 bits are only used for rounding the most significant 64
+        // bits.
+        final long kM32 = 0xFFFFFFFFL;
+        final long a = f_ >>> 32;
+        final long b = f_ & kM32;
+        final long c = other.f_ >>> 32;
+        final long d = other.f_ & kM32;
+        final long ac = a * c;
+        final long bc = b * c;
+        final long ad = a * d;
+        final long bd = b * d;
+        long tmp = (bd >>> 32) + (ad & kM32) + (bc & kM32);
+        // By adding 1U << 31 to tmp we round the final result.
+        // Halfway cases will be round up.
+        tmp += 1L << 31;
+        final long result_f = ac + (ad >>> 32) + (bc >>> 32) + (tmp >>> 32);
+        e_ += other.e_ + 64;
+        f_ = result_f;
+    }
+
+    // returns a * b;
+    static DiyFp times(final DiyFp a, final DiyFp b) {
+        final DiyFp result = new DiyFp(a.f_, a.e_);
+        result.multiply(b);
+        return result;
+    }
+
+    void normalize() {
+        assert(f_ != 0);
+        long significand = this.f_;
+        int exponent = this.e_;
+
+        // This method is mainly called for normalizing boundaries. In general
+        // boundaries need to be shifted by 10 bits. We thus optimize for this case.
+        final long k10MSBits = 0xFFC00000L << 32;
+        while ((significand & k10MSBits) == 0) {
+            significand <<= 10;
+            exponent -= 10;
+        }
+        while ((significand & kUint64MSB) == 0) {
+            significand <<= 1;
+            exponent--;
+        }
+        this.f_ = significand;
+        this.e_ = exponent;
+    }
+
+    static DiyFp normalize(final DiyFp a) {
+        final DiyFp result = new DiyFp(a.f_, a.e_);
+        result.normalize();
+        return result;
+    }
+
+    long f() { return f_; }
+    int e() { return e_; }
+
+    void setF(final long new_value) { f_ = new_value; }
+    void setE(final int new_value) { e_ = new_value; }
+
+    @Override
+    public String toString() {
+        return "DiyFp[f=" + f_ + ", e=" + e_ + "]";
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/doubleconv/DoubleConversion.java	Wed Nov 11 15:22:14 2015 +0100
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// This file is available under and governed by the GNU General Public
+// License version 2 only, as published by the Free Software Foundation.
+// However, the following notice accompanied the original version of this
+// file:
+//
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package jdk.nashorn.internal.runtime.doubleconv;
+
+/**
+ * This class provides the public API for the double conversion package.
+ */
+public final class DoubleConversion {
+
+    private final static int BUFFER_LENGTH = 30;
+
+    /**
+     * Converts a double number to its shortest string representation.
+     *
+     * @param value number to convert
+     * @return formatted number
+     */
+    public static String toShortestString(final double value) {
+        final DtoaBuffer buffer = new DtoaBuffer(FastDtoa.kFastDtoaMaximalLength);
+        final double absValue = Math.abs(value);
+
+        if (value < 0) {
+            buffer.isNegative = true;
+        }
+
+        if (!fastDtoaShortest(absValue, buffer)) {
+            buffer.reset();
+            bignumDtoa(absValue, DtoaMode.SHORTEST, 0, buffer);
+        }
+
+        return buffer.format(DtoaMode.SHORTEST, 0);
+    }
+
+    /**
+     * Converts a double number to a string representation with a fixed number of digits
+     * after the decimal point.
+     *
+     * @param value number to convert.
+     * @param requestedDigits number of digits after decimal point
+     * @return formatted number
+     */
+    public static String toFixed(final double value, final int requestedDigits) {
+        final DtoaBuffer buffer = new DtoaBuffer(BUFFER_LENGTH);
+        final double absValue = Math.abs(value);
+
+        if (value < 0) {
+            buffer.isNegative = true;
+        }
+
+        if (value == 0) {
+            buffer.append('0');
+            buffer.decimalPoint = 1;
+        } else if (!fixedDtoa(absValue, requestedDigits, buffer)) {
+            buffer.reset();
+            bignumDtoa(absValue, DtoaMode.FIXED, requestedDigits, buffer);
+        }
+
+        return buffer.format(DtoaMode.FIXED, requestedDigits);
+    }
+
+    /**
+     * Converts a double number to a string representation with a fixed number of digits.
+     *
+     * @param value number to convert
+     * @param precision number of digits to create
+     * @return formatted number
+     */
+    public static String toPrecision(final double value, final int precision) {
+        final DtoaBuffer buffer = new DtoaBuffer(precision);
+        final double absValue = Math.abs(value);
+
+        if (value < 0) {
+            buffer.isNegative = true;
+        }
+
+        if (value == 0) {
+            for (int i = 0; i < precision; i++) {
+                buffer.append('0');
+            }
+            buffer.decimalPoint = 1;
+
+        } else if (!fastDtoaCounted(absValue, precision, buffer)) {
+            buffer.reset();
+            bignumDtoa(absValue, DtoaMode.PRECISION, precision, buffer);
+        }
+
+        return buffer.format(DtoaMode.PRECISION, 0);
+    }
+
+    /**
+     * Converts a double number to a string representation using the
+     * {@code BignumDtoa} algorithm and the specified conversion mode
+     * and number of digits.
+     *
+     * @param v number to convert
+     * @param mode conversion mode
+     * @param digits number of digits
+     * @param buffer buffer to use
+     */
+    public static void bignumDtoa(final double v, final DtoaMode mode, final int digits, final DtoaBuffer buffer) {
+        assert(v > 0);
+        assert(!Double.isNaN(v));
+        assert(!Double.isInfinite(v));
+
+        BignumDtoa.bignumDtoa(v, mode, digits, buffer);
+    }
+
+    /**
+     * Converts a double number to its shortest string representation
+     * using the {@code FastDtoa} algorithm.
+     *
+     * @param v number to convert
+     * @param buffer buffer to use
+     * @return true if conversion succeeded
+     */
+    public static boolean fastDtoaShortest(final double v, final DtoaBuffer buffer) {
+        assert(v > 0);
+        assert(!Double.isNaN(v));
+        assert(!Double.isInfinite(v));
+
+        return FastDtoa.grisu3(v, buffer);
+    }
+
+    /**
+     * Converts a double number to a string representation with the
+     * given number of digits using the {@code FastDtoa} algorithm.
+     *
+     * @param v number to convert
+     * @param precision number of digits to generate
+     * @param buffer buffer to use
+     * @return true if conversion succeeded
+     */
+    public static boolean fastDtoaCounted(final double v, final int precision, final DtoaBuffer buffer) {
+        assert(v > 0);
+        assert(!Double.isNaN(v));
+        assert(!Double.isInfinite(v));
+
+        return FastDtoa.grisu3Counted(v, precision, buffer);
+    }
+
+    /**
+     * Converts a double number to a string representation with a
+     * fixed number of digits after the decimal point using the
+     * {@code FixedDtoa} algorithm.
+     *
+     * @param v number to convert.
+     * @param digits number of digits after the decimal point
+     * @param buffer buffer to use
+     * @return true if conversion succeeded
+     */
+    public static boolean fixedDtoa(final double v, final int digits, final DtoaBuffer buffer) {
+        assert(v > 0);
+        assert(!Double.isNaN(v));
+        assert(!Double.isInfinite(v));
+
+        return FixedDtoa.fastFixedDtoa(v, digits, buffer);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/doubleconv/DtoaBuffer.java	Wed Nov 11 15:22:14 2015 +0100
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// This file is available under and governed by the GNU General Public
+// License version 2 only, as published by the Free Software Foundation.
+// However, the following notice accompanied the original version of this
+// file:
+//
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package jdk.nashorn.internal.runtime.doubleconv;
+
+/**
+ * A buffer for generating string representations of doubles.
+ */
+public class DtoaBuffer {
+
+    // The character buffer
+    final char[] chars;
+
+    // The number of characters in the buffer
+    int length = 0;
+
+    // The position of the decimal point
+    int decimalPoint = 0;
+
+    // Is this a negative number?
+    boolean isNegative = false;
+
+    /**
+     * Maximal length of numbers converted by FastDtoa
+     */
+    public static final int kFastDtoaMaximalLength = FastDtoa.kFastDtoaMaximalLength;
+
+    /**
+     * Create a buffer with the given capacity.
+     * @param capacity the capacity of the buffer.
+     */
+    public DtoaBuffer(final int capacity) {
+        chars = new char[capacity];
+    }
+
+    /**
+     * Append a character to the buffer, increasing its length.
+     * @param c character
+     */
+    void append(final char c) {
+        chars[length++] = c;
+    }
+
+    /**
+     * Clear the buffer contents and set its length to {@code 0}.
+     */
+    public void reset() {
+        length = 0;
+        decimalPoint = 0;
+    }
+
+    /**
+     * Get the raw digits of this buffer as string.
+     * @return the raw buffer contents
+     */
+    public String getRawDigits() {
+        return new String(chars, 0, length);
+    }
+
+    /**
+     * Get the position of the decimal point.
+     * @return the decimal point position
+     */
+    public int getDecimalPoint() {
+        return decimalPoint;
+    }
+
+    /**
+     * Returns the number of characters in the buffer.
+     * @return buffer length
+     */
+    public int getLength() {
+        return length;
+    }
+
+    /**
+     * Returns the formatted buffer content as string, using the specified conversion mode
+     * and padding.
+     *
+     * @param mode conversion mode
+     * @param digitsAfterPoint number of digits after point
+     * @return formatted string
+     */
+    public String format(final DtoaMode mode, final int digitsAfterPoint) {
+        final StringBuilder buffer = new StringBuilder();
+        if (isNegative) {
+            buffer.append('-');
+        }
+
+        // check for minus sign
+        switch (mode) {
+            case SHORTEST:
+                if (decimalPoint < -5 || decimalPoint > 21) {
+                    toExponentialFormat(buffer);
+                } else {
+                    toFixedFormat(buffer, digitsAfterPoint);
+                }
+                break;
+            case FIXED:
+                toFixedFormat(buffer, digitsAfterPoint);
+                break;
+            case PRECISION:
+                if (decimalPoint < -5 || decimalPoint > length) {
+                    toExponentialFormat(buffer);
+                } else {
+                    toFixedFormat(buffer, digitsAfterPoint);
+                }
+                break;
+        }
+
+        return buffer.toString();
+    }
+
+    private void toFixedFormat(final StringBuilder buffer, final int digitsAfterPoint) {
+        if (decimalPoint <= 0) {
+            // < 1,
+            buffer.append('0');
+            if (length > 0) {
+                buffer.append('.');
+                final int padding = -decimalPoint;
+                for (int i = 0; i < padding; i++) {
+                    buffer.append('0');
+                }
+                buffer.append(chars, 0, length);
+            }
+        } else if (decimalPoint >= length) {
+            // large integer, add trailing zeroes
+            buffer.append(chars, 0, length);
+            for (int i = length; i < decimalPoint; i++) {
+                buffer.append('0');
+            }
+        } else if (decimalPoint < length) {
+            // >= 1, split decimals and insert decimalPoint
+            buffer.append(chars, 0, decimalPoint);
+            buffer.append('.');
+            buffer.append(chars, decimalPoint, length - decimalPoint);
+        }
+
+        // Create trailing zeros if requested
+        if (digitsAfterPoint > 0) {
+            if (decimalPoint >= length) {
+                buffer.append('.');
+            }
+            for (int i = Math.max(0, length - decimalPoint); i < digitsAfterPoint; i++) {
+                buffer.append('0');
+            }
+        }
+    }
+
+    private void toExponentialFormat(final StringBuilder buffer) {
+        buffer.append(chars[0]);
+        if (length > 1) {
+            // insert decimal decimalPoint if more than one digit was produced
+            buffer.append('.');
+            buffer.append(chars, 1, length - 1);
+        }
+        buffer.append('e');
+        final int exponent = decimalPoint - 1;
+        if (exponent > 0) {
+            buffer.append('+');
+        }
+        buffer.append(exponent);
+    }
+
+    @Override
+    public String toString() {
+        return "[chars:" + new String(chars, 0, length) + ", decimalPoint:" + decimalPoint + "]";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/doubleconv/DtoaMode.java	Wed Nov 11 15:22:14 2015 +0100
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// This file is available under and governed by the GNU General Public
+// License version 2 only, as published by the Free Software Foundation.
+// However, the following notice accompanied the original version of this
+// file:
+//
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package jdk.nashorn.internal.runtime.doubleconv;
+
+/**
+ * This defines the string conversion modes supported by this package.
+ * The original C++ library also supports SHORTEST-SINGLE for single
+ * precision floats but we don't since we always operate with doubles.
+ */
+public enum DtoaMode {
+    /**
+     * Produce the shortest correct representation.
+     * For example the output of 0.299999999999999988897 is (the less accurate
+     * but correct) 0.3.
+     */
+    SHORTEST,
+    /**
+     * Produce a fixed number of digits after the decimal point.
+     * For instance fixed(0.1, 4) becomes 0.1000
+     * If the input number is big, the output will be big.
+     */
+    FIXED,
+    /**
+     * Fixed number of digits (independent of the decimal point).
+     */
+    PRECISION
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/doubleconv/FastDtoa.java	Wed Nov 11 15:22:14 2015 +0100
@@ -0,0 +1,651 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// This file is available under and governed by the GNU General Public
+// License version 2 only, as published by the Free Software Foundation.
+// However, the following notice accompanied the original version of this
+// file:
+//
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package jdk.nashorn.internal.runtime.doubleconv;
+
+// Fast Dtoa implementation supporting shortest and precision modes. Does not
+// work for all numbers so BugnumDtoa is used as fallback.
+class FastDtoa {
+
+    // FastDtoa will produce at most kFastDtoaMaximalLength digits. This does not
+    // include the terminating '\0' character.
+    static final int kFastDtoaMaximalLength = 17;
+
+    // The minimal and maximal target exponent define the range of w's binary
+    // exponent, where 'w' is the result of multiplying the input by a cached power
+    // of ten.
+    //
+    // A different range might be chosen on a different platform, to optimize digit
+    // generation, but a smaller range requires more powers of ten to be cached.
+    static final int kMinimalTargetExponent = -60;
+    static final int kMaximalTargetExponent = -32;
+
+
+    // Adjusts the last digit of the generated number, and screens out generated
+    // solutions that may be inaccurate. A solution may be inaccurate if it is
+    // outside the safe interval, or if we cannot prove that it is closer to the
+    // input than a neighboring representation of the same length.
+    //
+    // Input: * buffer containing the digits of too_high / 10^kappa
+    //        * distance_too_high_w == (too_high - w).f() * unit
+    //        * unsafe_interval == (too_high - too_low).f() * unit
+    //        * rest = (too_high - buffer * 10^kappa).f() * unit
+    //        * ten_kappa = 10^kappa * unit
+    //        * unit = the common multiplier
+    // Output: returns true if the buffer is guaranteed to contain the closest
+    //    representable number to the input.
+    //  Modifies the generated digits in the buffer to approach (round towards) w.
+    static boolean roundWeed(final DtoaBuffer buffer,
+                             final long distance_too_high_w,
+                             final long unsafe_interval,
+                             long rest,
+                             final long ten_kappa,
+                             final long unit) {
+        final long small_distance = distance_too_high_w - unit;
+        final long big_distance = distance_too_high_w + unit;
+        // Let w_low  = too_high - big_distance, and
+        //     w_high = too_high - small_distance.
+        // Note: w_low < w < w_high
+        //
+        // The real w (* unit) must lie somewhere inside the interval
+        // ]w_low; w_high[ (often written as "(w_low; w_high)")
+
+        // Basically the buffer currently contains a number in the unsafe interval
+        // ]too_low; too_high[ with too_low < w < too_high
+        //
+        //  too_high - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+        //                     ^v 1 unit            ^      ^                 ^      ^
+        //  boundary_high ---------------------     .      .                 .      .
+        //                     ^v 1 unit            .      .                 .      .
+        //   - - - - - - - - - - - - - - - - - - -  +  - - + - - - - - -     .      .
+        //                                          .      .         ^       .      .
+        //                                          .  big_distance  .       .      .
+        //                                          .      .         .       .    rest
+        //                              small_distance     .         .       .      .
+        //                                          v      .         .       .      .
+        //  w_high - - - - - - - - - - - - - - - - - -     .         .       .      .
+        //                     ^v 1 unit                   .         .       .      .
+        //  w ----------------------------------------     .         .       .      .
+        //                     ^v 1 unit                   v         .       .      .
+        //  w_low  - - - - - - - - - - - - - - - - - - - - -         .       .      .
+        //                                                           .       .      v
+        //  buffer --------------------------------------------------+-------+--------
+        //                                                           .       .
+        //                                                  safe_interval    .
+        //                                                           v       .
+        //   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -     .
+        //                     ^v 1 unit                                     .
+        //  boundary_low -------------------------                     unsafe_interval
+        //                     ^v 1 unit                                     v
+        //  too_low  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+        //
+        //
+        // Note that the value of buffer could lie anywhere inside the range too_low
+        // to too_high.
+        //
+        // boundary_low, boundary_high and w are approximations of the real boundaries
+        // and v (the input number). They are guaranteed to be precise up to one unit.
+        // In fact the error is guaranteed to be strictly less than one unit.
+        //
+        // Anything that lies outside the unsafe interval is guaranteed not to round
+        // to v when read again.
+        // Anything that lies inside the safe interval is guaranteed to round to v
+        // when read again.
+        // If the number inside the buffer lies inside the unsafe interval but not
+        // inside the safe interval then we simply do not know and bail out (returning
+        // false).
+        //
+        // Similarly we have to take into account the imprecision of 'w' when finding
+        // the closest representation of 'w'. If we have two potential
+        // representations, and one is closer to both w_low and w_high, then we know
+        // it is closer to the actual value v.
+        //
+        // By generating the digits of too_high we got the largest (closest to
+        // too_high) buffer that is still in the unsafe interval. In the case where
+        // w_high < buffer < too_high we try to decrement the buffer.
+        // This way the buffer approaches (rounds towards) w.
+        // There are 3 conditions that stop the decrementation process:
+        //   1) the buffer is already below w_high
+        //   2) decrementing the buffer would make it leave the unsafe interval
+        //   3) decrementing the buffer would yield a number below w_high and farther
+        //      away than the current number. In other words:
+        //              (buffer{-1} < w_high) && w_high - buffer{-1} > buffer - w_high
+        // Instead of using the buffer directly we use its distance to too_high.
+        // Conceptually rest ~= too_high - buffer
+        // We need to do the following tests in this order to avoid over- and
+        // underflows.
+        assert (Long.compareUnsigned(rest, unsafe_interval) <= 0);
+        while (Long.compareUnsigned(rest, small_distance) < 0 &&  // Negated condition 1
+                Long.compareUnsigned(unsafe_interval - rest, ten_kappa) >= 0 &&  // Negated condition 2
+                (Long.compareUnsigned(rest + ten_kappa, small_distance) < 0 ||  // buffer{-1} > w_high
+                        Long.compareUnsigned(small_distance - rest, rest + ten_kappa - small_distance) >= 0)) {
+            buffer.chars[buffer.length - 1]--;
+            rest += ten_kappa;
+        }
+
+        // We have approached w+ as much as possible. We now test if approaching w-
+        // would require changing the buffer. If yes, then we have two possible
+        // representations close to w, but we cannot decide which one is closer.
+        if (Long.compareUnsigned(rest, big_distance) < 0 &&
+                Long.compareUnsigned(unsafe_interval - rest, ten_kappa) >= 0 &&
+                (Long.compareUnsigned(rest + ten_kappa, big_distance) < 0 ||
+                        Long.compareUnsigned(big_distance - rest, rest + ten_kappa - big_distance) > 0)) {
+            return false;
+        }
+
+        // Weeding test.
+        //   The safe interval is [too_low + 2 ulp; too_high - 2 ulp]
+        //   Since too_low = too_high - unsafe_interval this is equivalent to
+        //      [too_high - unsafe_interval + 4 ulp; too_high - 2 ulp]
+        //   Conceptually we have: rest ~= too_high - buffer
+        return Long.compareUnsigned(2 * unit, rest) <= 0 && Long.compareUnsigned(rest, unsafe_interval - 4 * unit) <= 0;
+    }
+
+    // Rounds the buffer upwards if the result is closer to v by possibly adding
+    // 1 to the buffer. If the precision of the calculation is not sufficient to
+    // round correctly, return false.
+    // The rounding might shift the whole buffer in which case the kappa is
+    // adjusted. For example "99", kappa = 3 might become "10", kappa = 4.
+    //
+    // If 2*rest > ten_kappa then the buffer needs to be round up.
+    // rest can have an error of +/- 1 unit. This function accounts for the
+    // imprecision and returns false, if the rounding direction cannot be
+    // unambiguously determined.
+    //
+    // Precondition: rest < ten_kappa.
+    // Changed return type to int to let caller know they should increase kappa (return value 2)
+    static int roundWeedCounted(final char[] buffer,
+                                final int length,
+                                final long rest,
+                                final long  ten_kappa,
+                                final long  unit) {
+        assert(Long.compareUnsigned(rest, ten_kappa) < 0);
+        // The following tests are done in a specific order to avoid overflows. They
+        // will work correctly with any uint64 values of rest < ten_kappa and unit.
+        //
+        // If the unit is too big, then we don't know which way to round. For example
+        // a unit of 50 means that the real number lies within rest +/- 50. If
+        // 10^kappa == 40 then there is no way to tell which way to round.
+        if (Long.compareUnsigned(unit, ten_kappa) >= 0) return 0;
+        // Even if unit is just half the size of 10^kappa we are already completely
+        // lost. (And after the previous test we know that the expression will not
+        // over/underflow.)
+        if (Long.compareUnsigned(ten_kappa - unit, unit) <= 0) return 0;
+        // If 2 * (rest + unit) <= 10^kappa we can safely round down.
+        if (Long.compareUnsigned(ten_kappa - rest, rest) > 0 && Long.compareUnsigned(ten_kappa - 2 * rest, 2 * unit) >= 0) {
+            return 1;
+        }
+        // If 2 * (rest - unit) >= 10^kappa, then we can safely round up.
+        if (Long.compareUnsigned(rest, unit) > 0 && Long.compareUnsigned(ten_kappa - (rest - unit), (rest - unit)) <= 0) {
+            // Increment the last digit recursively until we find a non '9' digit.
+            buffer[length - 1]++;
+            for (int i = length - 1; i > 0; --i) {
+                if (buffer[i] != '0' + 10) break;
+                buffer[i] = '0';
+                buffer[i - 1]++;
+            }
+            // If the first digit is now '0'+ 10 we had a buffer with all '9's. With the
+            // exception of the first digit all digits are now '0'. Simply switch the
+            // first digit to '1' and adjust the kappa. Example: "99" becomes "10" and
+            // the power (the kappa) is increased.
+            if (buffer[0] == '0' + 10) {
+                buffer[0] = '1';
+                // Return value of 2 tells caller to increase (*kappa) += 1
+                return 2;
+            }
+            return 1;
+        }
+        return 0;
+    }
+
+    // Returns the biggest power of ten that is less than or equal to the given
+    // number. We furthermore receive the maximum number of bits 'number' has.
+    //
+    // Returns power == 10^(exponent_plus_one-1) such that
+    //    power <= number < power * 10.
+    // If number_bits == 0 then 0^(0-1) is returned.
+    // The number of bits must be <= 32.
+    // Precondition: number < (1 << (number_bits + 1)).
+
+    // Inspired by the method for finding an integer log base 10 from here:
+    // http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
+    static final int kSmallPowersOfTen[] =
+    {0, 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000,
+            1000000000};
+
+    // Returns the biggest power of ten that is less than or equal than the given
+    // number. We furthermore receive the maximum number of bits 'number' has.
+    // If number_bits == 0 then 0^-1 is returned
+    // The number of bits must be <= 32.
+    // Precondition: (1 << number_bits) <= number < (1 << (number_bits + 1)).
+    static long biggestPowerTen(final int number,
+                                final int number_bits) {
+        final int power, exponent_plus_one;
+        assert ((number & 0xFFFFFFFFL) < (1l << (number_bits + 1)));
+        // 1233/4096 is approximately 1/lg(10).
+        int exponent_plus_one_guess = ((number_bits + 1) * 1233 >>> 12);
+        // We increment to skip over the first entry in the kPowersOf10 table.
+        // Note: kPowersOf10[i] == 10^(i-1).
+        exponent_plus_one_guess++;
+        // We don't have any guarantees that 2^number_bits <= number.
+        if (number < kSmallPowersOfTen[exponent_plus_one_guess]) {
+            exponent_plus_one_guess--;
+        }
+        power = kSmallPowersOfTen[exponent_plus_one_guess];
+        exponent_plus_one = exponent_plus_one_guess;
+
+        return ((long) power << 32) | (long) exponent_plus_one;
+    }
+
+    // Generates the digits of input number w.
+    // w is a floating-point number (DiyFp), consisting of a significand and an
+    // exponent. Its exponent is bounded by kMinimalTargetExponent and
+    // kMaximalTargetExponent.
+    //       Hence -60 <= w.e() <= -32.
+    //
+    // Returns false if it fails, in which case the generated digits in the buffer
+    // should not be used.
+    // Preconditions:
+    //  * low, w and high are correct up to 1 ulp (unit in the last place). That
+    //    is, their error must be less than a unit of their last digits.
+    //  * low.e() == w.e() == high.e()
+    //  * low < w < high, and taking into account their error: low~ <= high~
+    //  * kMinimalTargetExponent <= w.e() <= kMaximalTargetExponent
+    // Postconditions: returns false if procedure fails.
+    //   otherwise:
+    //     * buffer is not null-terminated, but len contains the number of digits.
+    //     * buffer contains the shortest possible decimal digit-sequence
+    //       such that LOW < buffer * 10^kappa < HIGH, where LOW and HIGH are the
+    //       correct values of low and high (without their error).
+    //     * if more than one decimal representation gives the minimal number of
+    //       decimal digits then the one closest to W (where W is the correct value
+    //       of w) is chosen.
+    // Remark: this procedure takes into account the imprecision of its input
+    //   numbers. If the precision is not enough to guarantee all the postconditions
+    //   then false is returned. This usually happens rarely (~0.5%).
+    //
+    // Say, for the sake of example, that
+    //   w.e() == -48, and w.f() == 0x1234567890abcdef
+    // w's value can be computed by w.f() * 2^w.e()
+    // We can obtain w's integral digits by simply shifting w.f() by -w.e().
+    //  -> w's integral part is 0x1234
+    //  w's fractional part is therefore 0x567890abcdef.
+    // Printing w's integral part is easy (simply print 0x1234 in decimal).
+    // In order to print its fraction we repeatedly multiply the fraction by 10 and
+    // get each digit. Example the first digit after the point would be computed by
+    //   (0x567890abcdef * 10) >> 48. -> 3
+    // The whole thing becomes slightly more complicated because we want to stop
+    // once we have enough digits. That is, once the digits inside the buffer
+    // represent 'w' we can stop. Everything inside the interval low - high
+    // represents w. However we have to pay attention to low, high and w's
+    // imprecision.
+    static boolean digitGen(final DiyFp low,
+                            final DiyFp w,
+                            final DiyFp high,
+                            final DtoaBuffer buffer,
+                            final int mk) {
+        assert(low.e() == w.e() && w.e() == high.e());
+        assert Long.compareUnsigned(low.f() + 1, high.f() - 1) <= 0;
+        assert(kMinimalTargetExponent <= w.e() && w.e() <= kMaximalTargetExponent);
+        // low, w and high are imprecise, but by less than one ulp (unit in the last
+        // place).
+        // If we remove (resp. add) 1 ulp from low (resp. high) we are certain that
+        // the new numbers are outside of the interval we want the final
+        // representation to lie in.
+        // Inversely adding (resp. removing) 1 ulp from low (resp. high) would yield
+        // numbers that are certain to lie in the interval. We will use this fact
+        // later on.
+        // We will now start by generating the digits within the uncertain
+        // interval. Later we will weed out representations that lie outside the safe
+        // interval and thus _might_ lie outside the correct interval.
+        long unit = 1;
+        final DiyFp too_low = new DiyFp(low.f() - unit, low.e());
+        final DiyFp too_high = new DiyFp(high.f() + unit, high.e());
+        // too_low and too_high are guaranteed to lie outside the interval we want the
+        // generated number in.
+        final DiyFp unsafe_interval = DiyFp.minus(too_high, too_low);
+        // We now cut the input number into two parts: the integral digits and the
+        // fractionals. We will not write any decimal separator though, but adapt
+        // kappa instead.
+        // Reminder: we are currently computing the digits (stored inside the buffer)
+        // such that:   too_low < buffer * 10^kappa < too_high
+        // We use too_high for the digit_generation and stop as soon as possible.
+        // If we stop early we effectively round down.
+        final DiyFp one = new DiyFp(1l << -w.e(), w.e());
+        // Division by one is a shift.
+        int integrals = (int)(too_high.f() >>> -one.e());
+        // Modulo by one is an and.
+        long fractionals = too_high.f() & (one.f() - 1);
+        int divisor;
+        final int divisor_exponent_plus_one;
+        final long result = biggestPowerTen(integrals, DiyFp.kSignificandSize - (-one.e()));
+        divisor = (int) (result >>> 32);
+        divisor_exponent_plus_one = (int) result;
+        int kappa = divisor_exponent_plus_one;
+        // Loop invariant: buffer = too_high / 10^kappa  (integer division)
+        // The invariant holds for the first iteration: kappa has been initialized
+        // with the divisor exponent + 1. And the divisor is the biggest power of ten
+        // that is smaller than integrals.
+        while (kappa > 0) {
+            final int digit = integrals / divisor;
+            assert (digit <= 9);
+            buffer.append((char) ('0' + digit));
+            integrals %= divisor;
+            kappa--;
+            // Note that kappa now equals the exponent of the divisor and that the
+            // invariant thus holds again.
+            final long rest =
+                    ((long) integrals << -one.e()) + fractionals;
+            // Invariant: too_high = buffer * 10^kappa + DiyFp(rest, one.e())
+            // Reminder: unsafe_interval.e() == one.e()
+            if (Long.compareUnsigned(rest, unsafe_interval.f()) < 0) {
+                // Rounding down (by not emitting the remaining digits) yields a number
+                // that lies within the unsafe interval.
+                buffer.decimalPoint = buffer.length - mk + kappa;
+                return roundWeed(buffer, DiyFp.minus(too_high, w).f(),
+                        unsafe_interval.f(), rest,
+                        (long) divisor << -one.e(), unit);
+            }
+            divisor /= 10;
+        }
+
+        // The integrals have been generated. We are at the point of the decimal
+        // separator. In the following loop we simply multiply the remaining digits by
+        // 10 and divide by one. We just need to pay attention to multiply associated
+        // data (like the interval or 'unit'), too.
+        // Note that the multiplication by 10 does not overflow, because w.e >= -60
+        // and thus one.e >= -60.
+        assert (one.e() >= -60);
+        assert (fractionals < one.f());
+        assert (Long.compareUnsigned(Long.divideUnsigned(0xFFFFFFFFFFFFFFFFL, 10), one.f()) >= 0);
+        for (;;) {
+            fractionals *= 10;
+            unit *= 10;
+            unsafe_interval.setF(unsafe_interval.f() * 10);
+            // Integer division by one.
+            final int digit = (int) (fractionals >>> -one.e());
+            assert (digit <= 9);
+            buffer.append((char) ('0' + digit));
+            fractionals &= one.f() - 1;  // Modulo by one.
+            kappa--;
+            if (Long.compareUnsigned(fractionals, unsafe_interval.f()) < 0) {
+                buffer.decimalPoint = buffer.length - mk + kappa;
+                return roundWeed(buffer, DiyFp.minus(too_high, w).f() * unit,
+                        unsafe_interval.f(), fractionals, one.f(), unit);
+            }
+        }
+    }
+
+    // Generates (at most) requested_digits digits of input number w.
+    // w is a floating-point number (DiyFp), consisting of a significand and an
+    // exponent. Its exponent is bounded by kMinimalTargetExponent and
+    // kMaximalTargetExponent.
+    //       Hence -60 <= w.e() <= -32.
+    //
+    // Returns false if it fails, in which case the generated digits in the buffer
+    // should not be used.
+    // Preconditions:
+    //  * w is correct up to 1 ulp (unit in the last place). That
+    //    is, its error must be strictly less than a unit of its last digit.
+    //  * kMinimalTargetExponent <= w.e() <= kMaximalTargetExponent
+    //
+    // Postconditions: returns false if procedure fails.
+    //   otherwise:
+    //     * buffer is not null-terminated, but length contains the number of
+    //       digits.
+    //     * the representation in buffer is the most precise representation of
+    //       requested_digits digits.
+    //     * buffer contains at most requested_digits digits of w. If there are less
+    //       than requested_digits digits then some trailing '0's have been removed.
+    //     * kappa is such that
+    //            w = buffer * 10^kappa + eps with |eps| < 10^kappa / 2.
+    //
+    // Remark: This procedure takes into account the imprecision of its input
+    //   numbers. If the precision is not enough to guarantee all the postconditions
+    //   then false is returned. This usually happens rarely, but the failure-rate
+    //   increases with higher requested_digits.
+    static boolean digitGenCounted(final DiyFp w,
+                                   int requested_digits,
+                                   final DtoaBuffer buffer,
+                                   final int mk) {
+        assert (kMinimalTargetExponent <= w.e() && w.e() <= kMaximalTargetExponent);
+        assert (kMinimalTargetExponent >= -60);
+        assert (kMaximalTargetExponent <= -32);
+        // w is assumed to have an error less than 1 unit. Whenever w is scaled we
+        // also scale its error.
+        long w_error = 1;
+        // We cut the input number into two parts: the integral digits and the
+        // fractional digits. We don't emit any decimal separator, but adapt kappa
+        // instead. Example: instead of writing "1.2" we put "12" into the buffer and
+        // increase kappa by 1.
+        final DiyFp one = new DiyFp(1l << -w.e(), w.e());
+        // Division by one is a shift.
+        int integrals = (int) (w.f() >>> -one.e());
+        // Modulo by one is an and.
+        long fractionals = w.f() & (one.f() - 1);
+        int divisor;
+        final int divisor_exponent_plus_one;
+        final long biggestPower = biggestPowerTen(integrals, DiyFp.kSignificandSize - (-one.e()));
+        divisor = (int) (biggestPower >>> 32);
+        divisor_exponent_plus_one = (int) biggestPower;
+        int kappa = divisor_exponent_plus_one;
+
+        // Loop invariant: buffer = w / 10^kappa  (integer division)
+        // The invariant holds for the first iteration: kappa has been initialized
+        // with the divisor exponent + 1. And the divisor is the biggest power of ten
+        // that is smaller than 'integrals'.
+        while (kappa > 0) {
+            final int digit = integrals / divisor;
+            assert (digit <= 9);
+            buffer.append((char) ('0' + digit));
+            requested_digits--;
+            integrals %= divisor;
+            kappa--;
+            // Note that kappa now equals the exponent of the divisor and that the
+            // invariant thus holds again.
+            if (requested_digits == 0) break;
+            divisor /= 10;
+        }
+
+        if (requested_digits == 0) {
+            final long rest =
+                    ((long) (integrals) << -one.e()) + fractionals;
+            final int result = roundWeedCounted(buffer.chars, buffer.length, rest,
+                    (long) divisor << -one.e(), w_error);
+            buffer.decimalPoint = buffer.length - mk + kappa + (result == 2 ? 1 : 0);
+            return result > 0;
+        }
+
+        // The integrals have been generated. We are at the decimalPoint of the decimal
+        // separator. In the following loop we simply multiply the remaining digits by
+        // 10 and divide by one. We just need to pay attention to multiply associated
+        // data (the 'unit'), too.
+        // Note that the multiplication by 10 does not overflow, because w.e >= -60
+        // and thus one.e >= -60.
+        assert (one.e() >= -60);
+        assert (fractionals < one.f());
+        assert (Long.compareUnsigned(Long.divideUnsigned(0xFFFFFFFFFFFFFFFFL, 10), one.f()) >= 0);
+        while (requested_digits > 0 && fractionals > w_error) {
+            fractionals *= 10;
+            w_error *= 10;
+            // Integer division by one.
+            final int digit = (int) (fractionals >>> -one.e());
+            assert (digit <= 9);
+            buffer.append((char) ('0' + digit));
+            requested_digits--;
+            fractionals &= one.f() - 1;  // Modulo by one.
+            kappa--;
+        }
+        if (requested_digits != 0) return false;
+        final int result = roundWeedCounted(buffer.chars, buffer.length, fractionals, one.f(), w_error);
+        buffer.decimalPoint = buffer.length - mk + kappa + (result == 2 ? 1 : 0);
+        return result > 0;
+    }
+
+
+    // Provides a decimal representation of v.
+    // Returns true if it succeeds, otherwise the result cannot be trusted.
+    // There will be *length digits inside the buffer (not null-terminated).
+    // If the function returns true then
+    //        v == (double) (buffer * 10^decimal_exponent).
+    // The digits in the buffer are the shortest representation possible: no
+    // 0.09999999999999999 instead of 0.1. The shorter representation will even be
+    // chosen even if the longer one would be closer to v.
+    // The last digit will be closest to the actual v. That is, even if several
+    // digits might correctly yield 'v' when read again, the closest will be
+    // computed.
+    static boolean grisu3(final double v, final DtoaBuffer buffer) {
+        final long d64 = IeeeDouble.doubleToLong(v);
+        final DiyFp w = IeeeDouble.asNormalizedDiyFp(d64);
+        // boundary_minus and boundary_plus are the boundaries between v and its
+        // closest floating-point neighbors. Any number strictly between
+        // boundary_minus and boundary_plus will round to v when convert to a double.
+        // Grisu3 will never output representations that lie exactly on a boundary.
+        final DiyFp boundary_minus = new DiyFp(), boundary_plus = new DiyFp();
+        IeeeDouble.normalizedBoundaries(d64, boundary_minus, boundary_plus);
+        assert(boundary_plus.e() == w.e());
+        final DiyFp ten_mk = new DiyFp();  // Cached power of ten: 10^-k
+        final int mk;                      // -k
+        final int ten_mk_minimal_binary_exponent =
+                kMinimalTargetExponent - (w.e() + DiyFp.kSignificandSize);
+        final int ten_mk_maximal_binary_exponent =
+                kMaximalTargetExponent - (w.e() + DiyFp.kSignificandSize);
+        mk = CachedPowers.getCachedPowerForBinaryExponentRange(
+                ten_mk_minimal_binary_exponent,
+                ten_mk_maximal_binary_exponent,
+           ten_mk);
+        assert(kMinimalTargetExponent <= w.e() + ten_mk.e() +
+                DiyFp.kSignificandSize &&
+                kMaximalTargetExponent >= w.e() + ten_mk.e() +
+                        DiyFp.kSignificandSize);
+        // Note that ten_mk is only an approximation of 10^-k. A DiyFp only contains a
+        // 64 bit significand and ten_mk is thus only precise up to 64 bits.
+
+        // The DiyFp::Times procedure rounds its result, and ten_mk is approximated
+        // too. The variable scaled_w (as well as scaled_boundary_minus/plus) are now
+        // off by a small amount.
+        // In fact: scaled_w - w*10^k < 1ulp (unit in the last place) of scaled_w.
+        // In other words: let f = scaled_w.f() and e = scaled_w.e(), then
+        //           (f-1) * 2^e < w*10^k < (f+1) * 2^e
+        final DiyFp scaled_w = DiyFp.times(w, ten_mk);
+        assert(scaled_w.e() ==
+                boundary_plus.e() + ten_mk.e() + DiyFp.kSignificandSize);
+        // In theory it would be possible to avoid some recomputations by computing
+        // the difference between w and boundary_minus/plus (a power of 2) and to
+        // compute scaled_boundary_minus/plus by subtracting/adding from
+        // scaled_w. However the code becomes much less readable and the speed
+        // enhancements are not terriffic.
+        final DiyFp scaled_boundary_minus = DiyFp.times(boundary_minus, ten_mk);
+        final DiyFp scaled_boundary_plus  = DiyFp.times(boundary_plus,  ten_mk);
+
+        // DigitGen will generate the digits of scaled_w. Therefore we have
+        // v == (double) (scaled_w * 10^-mk).
+        // Set decimal_exponent == -mk and pass it to DigitGen. If scaled_w is not an
+        // integer than it will be updated. For instance if scaled_w == 1.23 then
+        // the buffer will be filled with "123" und the decimal_exponent will be
+        // decreased by 2.
+        final boolean result = digitGen(scaled_boundary_minus, scaled_w, scaled_boundary_plus,
+                buffer, mk);
+        return result;
+    }
+
+    // The "counted" version of grisu3 (see above) only generates requested_digits
+    // number of digits. This version does not generate the shortest representation,
+    // and with enough requested digits 0.1 will at some point print as 0.9999999...
+    // Grisu3 is too imprecise for real halfway cases (1.5 will not work) and
+    // therefore the rounding strategy for halfway cases is irrelevant.
+    static boolean grisu3Counted(final double v,
+                                 final int requested_digits,
+                                 final DtoaBuffer buffer) {
+        final long d64 = IeeeDouble.doubleToLong(v);
+        final DiyFp w = IeeeDouble.asNormalizedDiyFp(d64);
+        final DiyFp ten_mk = new DiyFp();  // Cached power of ten: 10^-k
+        final int mk;                      // -k
+        final int ten_mk_minimal_binary_exponent =
+                kMinimalTargetExponent - (w.e() + DiyFp.kSignificandSize);
+        final int ten_mk_maximal_binary_exponent =
+                kMaximalTargetExponent - (w.e() + DiyFp.kSignificandSize);
+        mk = CachedPowers.getCachedPowerForBinaryExponentRange(
+                ten_mk_minimal_binary_exponent,
+                ten_mk_maximal_binary_exponent,
+                ten_mk);
+        assert ((kMinimalTargetExponent <= w.e() + ten_mk.e() +
+                DiyFp.kSignificandSize) &&
+                (kMaximalTargetExponent >= w.e() + ten_mk.e() +
+                        DiyFp.kSignificandSize));
+        // Note that ten_mk is only an approximation of 10^-k. A DiyFp only contains a
+        // 64 bit significand and ten_mk is thus only precise up to 64 bits.
+
+        // The DiyFp::Times procedure rounds its result, and ten_mk is approximated
+        // too. The variable scaled_w (as well as scaled_boundary_minus/plus) are now
+        // off by a small amount.
+        // In fact: scaled_w - w*10^k < 1ulp (unit in the last place) of scaled_w.
+        // In other words: let f = scaled_w.f() and e = scaled_w.e(), then
+        //           (f-1) * 2^e < w*10^k < (f+1) * 2^e
+        final DiyFp scaled_w = DiyFp.times(w, ten_mk);
+
+        // We now have (double) (scaled_w * 10^-mk).
+        // DigitGen will generate the first requested_digits digits of scaled_w and
+        // return together with a kappa such that scaled_w ~= buffer * 10^kappa. (It
+        // will not always be exactly the same since DigitGenCounted only produces a
+        // limited number of digits.)
+        final boolean result = digitGenCounted(scaled_w, requested_digits,
+                buffer, mk);
+        return result;
+    }
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/doubleconv/FixedDtoa.java	Wed Nov 11 15:22:14 2015 +0100
@@ -0,0 +1,425 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// This file is available under and governed by the GNU General Public
+// License version 2 only, as published by the Free Software Foundation.
+// However, the following notice accompanied the original version of this
+// file:
+//
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package jdk.nashorn.internal.runtime.doubleconv;
+
+class FixedDtoa {
+
+    // Represents a 128bit type. This class should be replaced by a native type on
+    // platforms that support 128bit integers.
+    static class UInt128 {
+
+        private static final long kMask32 = 0xFFFFFFFFL;
+        // Value == (high_bits_ << 64) + low_bits_
+        private long high_bits_;
+        private long low_bits_;
+
+        UInt128(final long high_bits, final long low_bits) {
+            this.high_bits_ = high_bits;
+            this.low_bits_ = low_bits;
+        }
+
+        void multiply(final int multiplicand) {
+            long accumulator;
+
+            accumulator = (low_bits_ & kMask32) * multiplicand;
+            long part = accumulator & kMask32;
+            accumulator >>>= 32;
+            accumulator = accumulator + (low_bits_ >>> 32) * multiplicand;
+            low_bits_ = (accumulator << 32) + part;
+            accumulator >>>= 32;
+            accumulator = accumulator + (high_bits_ & kMask32) * multiplicand;
+            part = accumulator & kMask32;
+            accumulator >>>= 32;
+            accumulator = accumulator + (high_bits_ >>> 32) * multiplicand;
+            high_bits_ = (accumulator << 32) + part;
+            assert ((accumulator >>> 32) == 0);
+        }
+
+        void shift(final int shift_amount) {
+            assert (-64 <= shift_amount && shift_amount <= 64);
+            if (shift_amount == 0) {
+                return;
+            } else if (shift_amount == -64) {
+                high_bits_ = low_bits_;
+                low_bits_ = 0;
+            } else if (shift_amount == 64) {
+                low_bits_ = high_bits_;
+                high_bits_ = 0;
+            } else if (shift_amount <= 0) {
+                high_bits_ <<= -shift_amount;
+                high_bits_ += low_bits_ >>> (64 + shift_amount);
+                low_bits_ <<= -shift_amount;
+            } else {
+                low_bits_ >>>= shift_amount;
+                low_bits_ += high_bits_ << (64 - shift_amount);
+                high_bits_ >>>= shift_amount;
+            }
+        }
+
+        // Modifies *this to *this MOD (2^power).
+        // Returns *this DIV (2^power).
+        int divModPowerOf2(final int power) {
+            if (power >= 64) {
+                final int result = (int) (high_bits_ >>> (power - 64));
+                high_bits_ -= (long) (result) << (power - 64);
+                return result;
+            } else {
+                final long part_low = low_bits_ >>> power;
+                final long part_high = high_bits_ << (64 - power);
+                final int result = (int) (part_low + part_high);
+                high_bits_ = 0;
+                low_bits_ -= part_low << power;
+                return result;
+            }
+        }
+
+        boolean isZero() {
+            return high_bits_ == 0 && low_bits_ == 0;
+        }
+
+        int bitAt(final int position) {
+            if (position >= 64) {
+                return (int) (high_bits_ >>> (position - 64)) & 1;
+            } else {
+                return (int) (low_bits_ >>> position) & 1;
+            }
+        }
+
+    };
+
+
+    static final  int kDoubleSignificandSize = 53;  // Includes the hidden bit.
+
+
+    static void fillDigits32FixedLength(int number, final int requested_length,
+                                        final DtoaBuffer buffer) {
+        for (int i = requested_length - 1; i >= 0; --i) {
+            buffer.chars[buffer.length + i] = (char) ('0' + Integer.remainderUnsigned(number, 10));
+            number = Integer.divideUnsigned(number, 10);
+        }
+        buffer.length += requested_length;
+    }
+
+
+    static void fillDigits32(int number, final DtoaBuffer buffer) {
+        int number_length = 0;
+        // We fill the digits in reverse order and exchange them afterwards.
+        while (number != 0) {
+            final int digit = Integer.remainderUnsigned(number, 10);
+            number = Integer.divideUnsigned(number, 10);
+            buffer.chars[buffer.length + number_length] = (char) ('0' + digit);
+            number_length++;
+        }
+        // Exchange the digits.
+        int i = buffer.length;
+        int j = buffer.length + number_length - 1;
+        while (i < j) {
+            final char tmp = buffer.chars[i];
+            buffer.chars[i] = buffer.chars[j];
+            buffer.chars[j] = tmp;
+            i++;
+            j--;
+        }
+        buffer.length += number_length;
+    }
+
+
+    static void fillDigits64FixedLength(long number, final DtoaBuffer buffer) {
+        final int kTen7 = 10000000;
+        // For efficiency cut the number into 3 uint32_t parts, and print those.
+        final int part2 = (int) Long.remainderUnsigned(number, kTen7);
+        number = Long.divideUnsigned(number, kTen7);
+        final int part1 = (int) Long.remainderUnsigned(number, kTen7);
+        final int part0 = (int) Long.divideUnsigned(number, kTen7);
+
+        fillDigits32FixedLength(part0, 3, buffer);
+        fillDigits32FixedLength(part1, 7, buffer);
+        fillDigits32FixedLength(part2, 7, buffer);
+    }
+
+
+    static void FillDigits64(long number, final DtoaBuffer buffer) {
+        final int kTen7 = 10000000;
+        // For efficiency cut the number into 3 uint32_t parts, and print those.
+        final int part2 = (int) Long.remainderUnsigned(number, kTen7);
+        number = Long.divideUnsigned(number, kTen7);
+        final int part1 = (int) Long.remainderUnsigned(number, kTen7);
+        final int part0 = (int) Long.divideUnsigned(number, kTen7);
+
+        if (part0 != 0) {
+            fillDigits32(part0, buffer);
+            fillDigits32FixedLength(part1, 7, buffer);
+            fillDigits32FixedLength(part2, 7, buffer);
+        } else if (part1 != 0) {
+            fillDigits32(part1, buffer);
+            fillDigits32FixedLength(part2, 7, buffer);
+        } else {
+            fillDigits32(part2, buffer);
+        }
+    }
+
+
+    static void roundUp(final DtoaBuffer buffer) {
+        // An empty buffer represents 0.
+        if (buffer.length == 0) {
+            buffer.chars[0] = '1';
+            buffer.decimalPoint = 1;
+            buffer.length = 1;
+            return;
+        }
+        // Round the last digit until we either have a digit that was not '9' or until
+        // we reached the first digit.
+        buffer.chars[buffer.length - 1]++;
+        for (int i = buffer.length - 1; i > 0; --i) {
+            if (buffer.chars[i] != '0' + 10) {
+                return;
+            }
+            buffer.chars[i] = '0';
+            buffer.chars[i - 1]++;
+        }
+        // If the first digit is now '0' + 10, we would need to set it to '0' and add
+        // a '1' in front. However we reach the first digit only if all following
+        // digits had been '9' before rounding up. Now all trailing digits are '0' and
+        // we simply switch the first digit to '1' and update the decimal-point
+        // (indicating that the point is now one digit to the right).
+        if (buffer.chars[0] == '0' + 10) {
+            buffer.chars[0] = '1';
+            buffer.decimalPoint++;
+        }
+    }
+
+
+    // The given fractionals number represents a fixed-point number with binary
+    // point at bit (-exponent).
+    // Preconditions:
+    //   -128 <= exponent <= 0.
+    //   0 <= fractionals * 2^exponent < 1
+    //   The buffer holds the result.
+    // The function will round its result. During the rounding-process digits not
+    // generated by this function might be updated, and the decimal-point variable
+    // might be updated. If this function generates the digits 99 and the buffer
+    // already contained "199" (thus yielding a buffer of "19999") then a
+    // rounding-up will change the contents of the buffer to "20000".
+    static void fillFractionals(long fractionals, final int exponent,
+                                final int fractional_count, final DtoaBuffer buffer) {
+        assert (-128 <= exponent && exponent <= 0);
+        // 'fractionals' is a fixed-decimalPoint number, with binary decimalPoint at bit
+        // (-exponent). Inside the function the non-converted remainder of fractionals
+        // is a fixed-decimalPoint number, with binary decimalPoint at bit 'decimalPoint'.
+        if (-exponent <= 64) {
+            // One 64 bit number is sufficient.
+            assert (fractionals >>> 56 == 0);
+            int point = -exponent;
+            for (int i = 0; i < fractional_count; ++i) {
+                if (fractionals == 0) break;
+                // Instead of multiplying by 10 we multiply by 5 and adjust the point
+                // location. This way the fractionals variable will not overflow.
+                // Invariant at the beginning of the loop: fractionals < 2^point.
+                // Initially we have: point <= 64 and fractionals < 2^56
+                // After each iteration the point is decremented by one.
+                // Note that 5^3 = 125 < 128 = 2^7.
+                // Therefore three iterations of this loop will not overflow fractionals
+                // (even without the subtraction at the end of the loop body). At this
+                // time point will satisfy point <= 61 and therefore fractionals < 2^point
+                // and any further multiplication of fractionals by 5 will not overflow.
+                fractionals *= 5;
+                point--;
+                final int digit = (int) (fractionals >>> point);
+                assert (digit <= 9);
+                buffer.chars[buffer.length] = (char) ('0' + digit);
+                buffer.length++;
+                fractionals -= (long) (digit) << point;
+            }
+            // If the first bit after the point is set we have to round up.
+            if (((fractionals >>> (point - 1)) & 1) == 1) {
+                roundUp(buffer);
+            }
+        } else {  // We need 128 bits.
+            assert (64 < -exponent && -exponent <= 128);
+            final UInt128 fractionals128 = new UInt128(fractionals, 0);
+            fractionals128.shift(-exponent - 64);
+            int point = 128;
+            for (int i = 0; i < fractional_count; ++i) {
+                if (fractionals128.isZero()) break;
+                // As before: instead of multiplying by 10 we multiply by 5 and adjust the
+                // point location.
+                // This multiplication will not overflow for the same reasons as before.
+                fractionals128.multiply(5);
+                point--;
+                final int digit = fractionals128.divModPowerOf2(point);
+                assert (digit <= 9);
+                buffer.chars[buffer.length] = (char) ('0' + digit);
+                buffer.length++;
+            }
+            if (fractionals128.bitAt(point - 1) == 1) {
+                roundUp(buffer);
+            }
+        }
+    }
+
+
+    // Removes leading and trailing zeros.
+    // If leading zeros are removed then the decimal point position is adjusted.
+    static void trimZeros(final DtoaBuffer buffer) {
+        while (buffer.length > 0 && buffer.chars[buffer.length - 1] == '0') {
+            buffer.length--;
+        }
+        int first_non_zero = 0;
+        while (first_non_zero < buffer.length && buffer.chars[first_non_zero] == '0') {
+            first_non_zero++;
+        }
+        if (first_non_zero != 0) {
+            for (int i = first_non_zero; i < buffer.length; ++i) {
+                buffer.chars[i - first_non_zero] = buffer.chars[i];
+            }
+            buffer.length -= first_non_zero;
+            buffer.decimalPoint -= first_non_zero;
+        }
+    }
+
+
+    static boolean fastFixedDtoa(final double v,
+                                 final int fractional_count,
+                                 final DtoaBuffer buffer) {
+        final long kMaxUInt32 = 0xFFFFFFFFL;
+        final long l = IeeeDouble.doubleToLong(v);
+        long significand = IeeeDouble.significand(l);
+        final int exponent = IeeeDouble.exponent(l);
+        // v = significand * 2^exponent (with significand a 53bit integer).
+        // If the exponent is larger than 20 (i.e. we may have a 73bit number) then we
+        // don't know how to compute the representation. 2^73 ~= 9.5*10^21.
+        // If necessary this limit could probably be increased, but we don't need
+        // more.
+        if (exponent > 20) return false;
+        if (fractional_count > 20) return false;
+        // At most kDoubleSignificandSize bits of the significand are non-zero.
+        // Given a 64 bit integer we have 11 0s followed by 53 potentially non-zero
+        // bits:  0..11*..0xxx..53*..xx
+        if (exponent + kDoubleSignificandSize > 64) {
+            // The exponent must be > 11.
+            //
+            // We know that v = significand * 2^exponent.
+            // And the exponent > 11.
+            // We simplify the task by dividing v by 10^17.
+            // The quotient delivers the first digits, and the remainder fits into a 64
+            // bit number.
+            // Dividing by 10^17 is equivalent to dividing by 5^17*2^17.
+            final long kFive17 = 0xB1A2BC2EC5L;  // 5^17
+            long divisor = kFive17;
+            final int divisor_power = 17;
+            long dividend = significand;
+            final int quotient;
+            final long remainder;
+            // Let v = f * 2^e with f == significand and e == exponent.
+            // Then need q (quotient) and r (remainder) as follows:
+            //   v            = q * 10^17       + r
+            //   f * 2^e      = q * 10^17       + r
+            //   f * 2^e      = q * 5^17 * 2^17 + r
+            // If e > 17 then
+            //   f * 2^(e-17) = q * 5^17        + r/2^17
+            // else
+            //   f  = q * 5^17 * 2^(17-e) + r/2^e
+            if (exponent > divisor_power) {
+                // We only allow exponents of up to 20 and therefore (17 - e) <= 3
+                dividend <<= exponent - divisor_power;
+                quotient = (int) Long.divideUnsigned(dividend, divisor);
+                remainder = Long.remainderUnsigned(dividend, divisor) << divisor_power;
+            } else {
+                divisor <<= divisor_power - exponent;
+                quotient = (int) Long.divideUnsigned(dividend, divisor);
+                remainder = Long.remainderUnsigned(dividend, divisor) << exponent;
+            }
+            fillDigits32(quotient, buffer);
+            fillDigits64FixedLength(remainder, buffer);
+            buffer.decimalPoint = buffer.length;
+        } else if (exponent >= 0) {
+            // 0 <= exponent <= 11
+            significand <<= exponent;
+            FillDigits64(significand, buffer);
+            buffer.decimalPoint = buffer.length;
+        } else if (exponent > -kDoubleSignificandSize) {
+            // We have to cut the number.
+            final long integrals = significand >>> -exponent;
+            final long fractionals = significand - (integrals << -exponent);
+            if (Long.compareUnsigned(integrals, kMaxUInt32) > 0) {
+                FillDigits64(integrals, buffer);
+            } else {
+                fillDigits32((int) (integrals), buffer);
+            }
+            buffer.decimalPoint = buffer.length;
+            fillFractionals(fractionals, exponent, fractional_count, buffer);
+        } else if (exponent < -128) {
+            // This configuration (with at most 20 digits) means that all digits must be
+            // 0.
+            assert (fractional_count <= 20);
+            buffer.reset();
+            buffer.decimalPoint = -fractional_count;
+        } else {
+            buffer.decimalPoint = 0;
+            fillFractionals(significand, exponent, fractional_count, buffer);
+        }
+        trimZeros(buffer);
+        if (buffer.length == 0) {
+            // The string is empty and the decimal_point thus has no importance. Mimick
+            // Gay's dtoa and and set it to -fractional_count.
+            buffer.decimalPoint = -fractional_count;
+        }
+        return true;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/doubleconv/IeeeDouble.java	Wed Nov 11 15:22:14 2015 +0100
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// This file is available under and governed by the GNU General Public
+// License version 2 only, as published by the Free Software Foundation.
+// However, the following notice accompanied the original version of this
+// file:
+//
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package jdk.nashorn.internal.runtime.doubleconv;
+
+// Helper functions for doubles.
+class IeeeDouble {
+
+    // We assume that doubles and long have the same endianness.
+    static long doubleToLong(final double d)   { return Double.doubleToRawLongBits(d); }
+    static double longToDouble(final long d64) { return Double.longBitsToDouble(d64); }
+
+    static final long kSignMask = 0x8000000000000000L;
+    static final long kExponentMask = 0x7FF0000000000000L;
+    static final long kSignificandMask = 0x000FFFFFFFFFFFFFL;
+    static final long kHiddenBit = 0x0010000000000000L;
+    static final int kPhysicalSignificandSize = 52;  // Excludes the hidden bit.
+    static final int kSignificandSize = 53;
+
+    static private final int kExponentBias = 0x3FF + kPhysicalSignificandSize;
+    static private final int kDenormalExponent = -kExponentBias + 1;
+    static private final int kMaxExponent = 0x7FF - kExponentBias;
+    static private final long kInfinity = 0x7FF0000000000000L;
+    static private final long kNaN = 0x7FF8000000000000L;
+
+    static DiyFp asDiyFp(final long d64) {
+        assert (!isSpecial(d64));
+        return new DiyFp(significand(d64), exponent(d64));
+    }
+
+    // The value encoded by this Double must be strictly greater than 0.
+    static DiyFp asNormalizedDiyFp(final long d64) {
+        assert (value(d64) > 0.0);
+        long f = significand(d64);
+        int e = exponent(d64);
+
+        // The current double could be a denormal.
+        while ((f & kHiddenBit) == 0) {
+            f <<= 1;
+            e--;
+        }
+        // Do the final shifts in one go.
+        f <<= DiyFp.kSignificandSize - kSignificandSize;
+        e -= DiyFp.kSignificandSize - kSignificandSize;
+
+        return new DiyFp(f, e);
+    }
+
+    // Returns the next greater double. Returns +infinity on input +infinity.
+    static double nextDouble(final long d64) {
+        if (d64 == kInfinity) return longToDouble(kInfinity);
+        if (sign(d64) < 0 && significand(d64) == 0) {
+            // -0.0
+            return 0.0;
+        }
+        if (sign(d64) < 0) {
+            return longToDouble(d64 - 1);
+        } else {
+            return longToDouble(d64 + 1);
+        }
+    }
+
+    static double previousDouble(final long d64) {
+        if (d64 == (kInfinity | kSignMask)) return -longToDouble(kInfinity);
+        if (sign(d64) < 0) {
+            return longToDouble(d64 + 1);
+        } else {
+            if (significand(d64) == 0) return -0.0;
+            return longToDouble(d64 - 1);
+        }
+    }
+
+    static int exponent(final long d64) {
+        if (isDenormal(d64)) return kDenormalExponent;
+
+        final int biased_e = (int) ((d64 & kExponentMask) >>> kPhysicalSignificandSize);
+        return biased_e - kExponentBias;
+    }
+
+    static long significand(final long d64) {
+        final long significand = d64 & kSignificandMask;
+        if (!isDenormal(d64)) {
+            return significand + kHiddenBit;
+        } else {
+            return significand;
+        }
+    }
+
+    // Returns true if the double is a denormal.
+    static boolean isDenormal(final long d64) {
+        return (d64 & kExponentMask) == 0L;
+    }
+
+    // We consider denormals not to be special.
+    // Hence only Infinity and NaN are special.
+    static boolean isSpecial(final long d64) {
+        return (d64 & kExponentMask) == kExponentMask;
+    }
+
+    static boolean isNaN(final long d64) {
+        return ((d64 & kExponentMask) == kExponentMask) &&
+                ((d64 & kSignificandMask) != 0L);
+    }
+
+
+    static boolean isInfinite(final long d64) {
+        return ((d64 & kExponentMask) == kExponentMask) &&
+                ((d64 & kSignificandMask) == 0L);
+    }
+
+
+    static int sign(final long d64) {
+        return (d64 & kSignMask) == 0L ? 1 : -1;
+    }
+
+
+    // Computes the two boundaries of this.
+    // The bigger boundary (m_plus) is normalized. The lower boundary has the same
+    // exponent as m_plus.
+    // Precondition: the value encoded by this Double must be greater than 0.
+    static void normalizedBoundaries(final long d64, final DiyFp m_minus, final DiyFp m_plus) {
+        assert (value(d64) > 0.0);
+        final DiyFp v = asDiyFp(d64);
+        m_plus.setF((v.f() << 1) + 1);
+        m_plus.setE(v.e() - 1);
+        m_plus.normalize();
+        if (lowerBoundaryIsCloser(d64)) {
+            m_minus.setF((v.f() << 2) - 1);
+            m_minus.setE(v.e() - 2);
+        } else {
+            m_minus.setF((v.f() << 1) - 1);
+            m_minus.setE(v.e() - 1);
+        }
+        m_minus.setF(m_minus.f() << (m_minus.e() - m_plus.e()));
+        m_minus.setE(m_plus.e());
+    }
+
+    static boolean lowerBoundaryIsCloser(final long d64) {
+        // The boundary is closer if the significand is of the form f == 2^p-1 then
+        // the lower boundary is closer.
+        // Think of v = 1000e10 and v- = 9999e9.
+        // Then the boundary (== (v - v-)/2) is not just at a distance of 1e9 but
+        // at a distance of 1e8.
+        // The only exception is for the smallest normal: the largest denormal is
+        // at the same distance as its successor.
+        // Note: denormals have the same exponent as the smallest normals.
+        final boolean physical_significand_is_zero = ((d64 & kSignificandMask) == 0);
+        return physical_significand_is_zero && (exponent(d64) != kDenormalExponent);
+    }
+
+    static double value(final long d64) {
+        return longToDouble(d64);
+    }
+
+    // Returns the significand size for a given order of magnitude.
+    // If v = f*2^e with 2^p-1 <= f <= 2^p then p+e is v's order of magnitude.
+    // This function returns the number of significant binary digits v will have
+    // once it's encoded into a double. In almost all cases this is equal to
+    // kSignificandSize. The only exceptions are denormals. They start with
+    // leading zeroes and their effective significand-size is hence smaller.
+    static int significandSizeForOrderOfMagnitude(final int order) {
+        if (order >= (kDenormalExponent + kSignificandSize)) {
+            return kSignificandSize;
+        }
+        if (order <= kDenormalExponent) return 0;
+        return order - kDenormalExponent;
+    }
+
+    static double Infinity() {
+        return longToDouble(kInfinity);
+    }
+
+    static double NaN() {
+        return longToDouble(kNaN);
+    }
+
+}
+
+
--- a/test/script/basic/JDK-8062141.js.EXPECTED	Wed Nov 11 14:54:09 2015 +0100
+++ b/test/script/basic/JDK-8062141.js.EXPECTED	Wed Nov 11 15:22:14 2015 +0100
@@ -114,7 +114,7 @@
 {"a":truer}
          ^
 [1,2,3]
-[9223372036854773800,9223372036854774800,9223372036854776000]
+[9223372036854774000,9223372036854775000,9223372036854776000]
 [1.1,1.2,1.3]
 [1,1.2,9223372036854776000,null,true]
 {"a":"string","b":1,"c":1.2,"d":9223372036854776000,"e":null,"f":true}
--- a/test/script/basic/NASHORN-389.js	Wed Nov 11 14:54:09 2015 +0100
+++ b/test/script/basic/NASHORN-389.js	Wed Nov 11 15:22:14 2015 +0100
@@ -35,6 +35,6 @@
 var y = -1.23456789e+20;
 print(x.toFixed(9));
 print(y.toFixed(9).indexOf(",") === -1); // no grouping
-//print(y.toFixed(9)); // FIXME expected: -123456788999999995904.000000000
-//print(1000000000000000128); // FIXME expected: 1000000000000000100
-//print((1000000000000000128).toFixed(0)); // FIXME expected: 1000000000000000128
+print(y.toFixed(9));
+print(1000000000000000128); 
+print((1000000000000000128).toFixed(0));
--- a/test/script/basic/NASHORN-389.js.EXPECTED	Wed Nov 11 14:54:09 2015 +0100
+++ b/test/script/basic/NASHORN-389.js.EXPECTED	Wed Nov 11 15:22:14 2015 +0100
@@ -3,3 +3,6 @@
 0.00001
 -1.23456789e+21
 true
+-123456788999999995904.000000000
+1000000000000000100
+1000000000000000128
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/src/jdk/nashorn/internal/runtime/doubleconv/test/BignumDtoaTest.java	Wed Nov 11 15:22:14 2015 +0100
@@ -0,0 +1,355 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// This file is available under and governed by the GNU General Public
+// License version 2 only, as published by the Free Software Foundation.
+// However, the following notice accompanied the original version of this
+// file:
+//
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package jdk.nashorn.internal.runtime.doubleconv.test;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import jdk.nashorn.internal.runtime.doubleconv.DoubleConversion;
+import jdk.nashorn.internal.runtime.doubleconv.DtoaBuffer;
+import jdk.nashorn.internal.runtime.doubleconv.DtoaMode;
+
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * FastDtoa tests
+ *
+ * @test
+ * @run testng jdk.nashorn.internal.runtime.doubleconv.test.FastDtoaTest
+ */
+@SuppressWarnings("javadoc")
+public class BignumDtoaTest {
+
+    final static private int BUFFER_SIZE = 100;
+
+    // Removes trailing '0' digits.
+    // Can return the empty string if all digits are 0.
+    private static String trimRepresentation(final String representation) {
+        final int len = representation.length();
+        int i;
+        for (i = len - 1; i >= 0; --i) {
+            if (representation.charAt(i) != '0') break;
+        }
+        return representation.substring(0, i + 1);
+    }
+
+    @Test
+    public void testBignumVarious() {
+        final DtoaBuffer buffer = new DtoaBuffer(BUFFER_SIZE);
+
+        DoubleConversion.bignumDtoa(1, DtoaMode.SHORTEST, 0, buffer);
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(1.0, DtoaMode.FIXED, 3, buffer);
+        assertTrue(3 >= buffer.getLength() - buffer.getDecimalPoint());
+        assertEquals("1", trimRepresentation(buffer.getRawDigits()));
+        assertEquals(1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(1.0, DtoaMode.PRECISION, 3, buffer);
+        assertTrue(3 >= buffer.getLength());
+        assertEquals("1", trimRepresentation(buffer.getRawDigits()));
+        assertEquals(1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(1.5, DtoaMode.SHORTEST, 0, buffer);
+        assertEquals("15", buffer.getRawDigits());
+        assertEquals(1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(1.5, DtoaMode.FIXED, 10, buffer);
+        assertTrue(10 >= buffer.getLength() - buffer.getDecimalPoint());
+        assertEquals("15", trimRepresentation(buffer.getRawDigits()));
+        assertEquals(1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(1.5, DtoaMode.PRECISION, 10, buffer);
+        assertTrue(10 >= buffer.getLength());
+        assertEquals("15", trimRepresentation(buffer.getRawDigits()));
+        assertEquals(1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        final double min_double = 5e-324;
+        DoubleConversion.bignumDtoa(min_double, DtoaMode.SHORTEST, 0, buffer);
+        assertEquals("5", buffer.getRawDigits());
+        assertEquals(-323, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(min_double, DtoaMode.FIXED, 5, buffer);
+        assertTrue(5 >= buffer.getLength() - buffer.getDecimalPoint());
+        assertEquals("", trimRepresentation(buffer.getRawDigits()));
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(min_double, DtoaMode.PRECISION, 5, buffer);
+        assertTrue(5 >= buffer.getLength());
+        assertEquals("49407", trimRepresentation(buffer.getRawDigits()));
+        assertEquals(-323, buffer.getDecimalPoint());
+        buffer.reset();
+
+        final double max_double = 1.7976931348623157e308;
+        DoubleConversion.bignumDtoa(max_double, DtoaMode.SHORTEST, 0, buffer);
+        assertEquals("17976931348623157", buffer.getRawDigits());
+        assertEquals(309, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(max_double, DtoaMode.PRECISION, 7, buffer);
+        assertTrue(7 >= buffer.getLength());
+        assertEquals("1797693", trimRepresentation(buffer.getRawDigits()));
+        assertEquals(309, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(4294967272.0, DtoaMode.SHORTEST, 0, buffer);
+        assertEquals("4294967272", buffer.getRawDigits());
+        assertEquals(10, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(4294967272.0, DtoaMode.FIXED, 5, buffer);
+        assertEquals("429496727200000", buffer.getRawDigits());
+        assertEquals(10, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(4294967272.0, DtoaMode.PRECISION, 14, buffer);
+        assertTrue(14 >= buffer.getLength());
+        assertEquals("4294967272", trimRepresentation(buffer.getRawDigits()));
+        assertEquals(10, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(4.1855804968213567e298, DtoaMode.SHORTEST, 0, buffer);
+        assertEquals("4185580496821357", buffer.getRawDigits());
+        assertEquals(299, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(4.1855804968213567e298, DtoaMode.PRECISION, 20, buffer);
+        assertTrue(20 >= buffer.getLength());
+        assertEquals("41855804968213567225", trimRepresentation(buffer.getRawDigits()));
+        assertEquals(299, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(5.5626846462680035e-309, DtoaMode.SHORTEST, 0, buffer);
+        assertEquals("5562684646268003", buffer.getRawDigits());
+        assertEquals(-308, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(5.5626846462680035e-309, DtoaMode.PRECISION, 1, buffer);
+        assertTrue(1 >= buffer.getLength());
+        assertEquals("6", trimRepresentation(buffer.getRawDigits()));
+        assertEquals(-308, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(2147483648.0, DtoaMode.SHORTEST, 0, buffer);
+        assertEquals("2147483648", buffer.getRawDigits());
+        assertEquals(10, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(2147483648.0, DtoaMode.FIXED, 2, buffer);
+        assertTrue(2 >= buffer.getLength() - buffer.getDecimalPoint());
+        assertEquals("2147483648", trimRepresentation(buffer.getRawDigits()));
+        assertEquals(10, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(2147483648.0, DtoaMode.PRECISION, 5, buffer);
+        assertTrue(5 >= buffer.getLength());
+        assertEquals("21475", trimRepresentation(buffer.getRawDigits()));
+        assertEquals(10, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(3.5844466002796428e+298, DtoaMode.SHORTEST, 0, buffer);
+        assertEquals("35844466002796428", buffer.getRawDigits());
+        assertEquals(299, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(3.5844466002796428e+298, DtoaMode.PRECISION, 10, buffer);
+        assertTrue(10 >= buffer.getLength());
+        assertEquals("35844466", trimRepresentation(buffer.getRawDigits()));
+        assertEquals(299, buffer.getDecimalPoint());
+        buffer.reset();
+
+        final long smallest_normal64 = 0x0010000000000000L;
+        double v = Double.longBitsToDouble(smallest_normal64);
+        DoubleConversion.bignumDtoa(v, DtoaMode.SHORTEST, 0, buffer);
+        assertEquals("22250738585072014", buffer.getRawDigits());
+        assertEquals(-307, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(v, DtoaMode.PRECISION, 20, buffer);
+        assertTrue(20 >= buffer.getLength());
+        assertEquals("22250738585072013831", trimRepresentation(buffer.getRawDigits()));
+        assertEquals(-307, buffer.getDecimalPoint());
+        buffer.reset();
+
+        final long largest_denormal64 = 0x000FFFFFFFFFFFFFL;
+        v = Double.longBitsToDouble(largest_denormal64);
+        DoubleConversion.bignumDtoa(v, DtoaMode.SHORTEST, 0, buffer);
+        assertEquals("2225073858507201", buffer.getRawDigits());
+        assertEquals(-307, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(v, DtoaMode.PRECISION, 20, buffer);
+        assertTrue(20 >= buffer.getLength());
+        assertEquals("2225073858507200889", trimRepresentation(buffer.getRawDigits()));
+        assertEquals(-307, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(4128420500802942e-24, DtoaMode.SHORTEST, 0, buffer);
+        assertEquals("4128420500802942", buffer.getRawDigits());
+        assertEquals(-8, buffer.getDecimalPoint());
+        buffer.reset();
+
+        DoubleConversion.bignumDtoa(3.9292015898194142585311918e-10, DtoaMode.SHORTEST, 0, buffer);
+        assertEquals("39292015898194143", buffer.getRawDigits());
+        buffer.reset();
+
+        v = 4194304.0;
+        DoubleConversion.bignumDtoa(v, DtoaMode.FIXED, 5, buffer);
+        assertTrue(5 >= buffer.getLength() - buffer.getDecimalPoint());
+        assertEquals("4194304", trimRepresentation(buffer.getRawDigits()));
+        buffer.reset();
+
+        v = 3.3161339052167390562200598e-237;
+        DoubleConversion.bignumDtoa(v, DtoaMode.PRECISION, 19, buffer);
+        assertTrue(19 >= buffer.getLength());
+        assertEquals("3316133905216739056", trimRepresentation(buffer.getRawDigits()));
+        assertEquals(-236, buffer.getDecimalPoint());
+        buffer.reset();
+
+        v = 7.9885183916008099497815232e+191;
+        DoubleConversion.bignumDtoa(v, DtoaMode.PRECISION, 4, buffer);
+        assertTrue(4 >= buffer.getLength());
+        assertEquals("7989", trimRepresentation(buffer.getRawDigits()));
+        assertEquals(192, buffer.getDecimalPoint());
+        buffer.reset();
+
+        v = 1.0000000000000012800000000e+17;
+        DoubleConversion.bignumDtoa(v, DtoaMode.FIXED, 1, buffer);
+        assertTrue(1 >= buffer.getLength() - buffer.getDecimalPoint());
+        assertEquals("100000000000000128", trimRepresentation(buffer.getRawDigits()));
+        assertEquals(18, buffer.getDecimalPoint());
+        buffer.reset();
+    }
+
+
+    @Test
+    public void testBignumShortest() {
+        new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("resources/gay-shortest.txt")))
+                .lines()
+                .forEach(line -> {
+                    if (line.isEmpty() || line.startsWith("//")) {
+                        return; // comment or empty line
+                    }
+                    final String[] tokens = line.split(",\\s+");
+                    assertEquals(tokens.length, 3, "*" + line + "*");
+                    final double v = Double.parseDouble(tokens[0]);
+                    final String str = tokens[1].replace('"', ' ').trim();;
+                    final int point = Integer.parseInt(tokens[2]);
+                    final DtoaBuffer buffer = new DtoaBuffer(BUFFER_SIZE);
+
+                    DoubleConversion.bignumDtoa(v, DtoaMode.SHORTEST, 0, buffer);
+                    assertEquals(str, buffer.getRawDigits());
+                    assertEquals(point, buffer.getDecimalPoint());
+                });
+    }
+
+    @Test
+    public void testBignumFixed()  {
+        new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("resources/gay-fixed.txt")))
+                .lines()
+                .forEach(line -> {
+                    if (line.isEmpty() || line.startsWith("//")) {
+                        return; // comment or empty line
+                    }
+                    final String[] tokens = line.split(",\\s+");
+                    assertEquals(tokens.length, 4);
+                    final double v = Double.parseDouble(tokens[0]);
+                    final int digits = Integer.parseInt(tokens[1]);
+                    final String str = tokens[2].replace('"', ' ').trim();
+                    final int point = Integer.parseInt(tokens[3]);
+                    final DtoaBuffer buffer = new DtoaBuffer(BUFFER_SIZE);
+
+                    DoubleConversion.bignumDtoa(v, DtoaMode.FIXED, digits, buffer);
+                    assertEquals(str, trimRepresentation(buffer.getRawDigits()));
+                    assertEquals(point, buffer.getDecimalPoint());
+                });
+    }
+
+    @Test
+    public void testBignumPrecision() {
+        new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("resources/gay-precision.txt")))
+                .lines()
+                .forEach(line -> {
+                    if (line.isEmpty() || line.startsWith("//")) {
+                        return; // comment or empty line
+                    }
+                    final String[] tokens = line.split(",\\s+");
+                    assertEquals(tokens.length, 4);
+                    final double v = Double.parseDouble(tokens[0]);
+                    final int digits = Integer.parseInt(tokens[1]);
+                    final String str = tokens[2].replace('"', ' ').trim();
+                    final int point = Integer.parseInt(tokens[3]);
+                    final DtoaBuffer buffer = new DtoaBuffer(BUFFER_SIZE);
+
+                    DoubleConversion.bignumDtoa(v, DtoaMode.PRECISION, digits, buffer);
+                    assertEquals(str, trimRepresentation(buffer.getRawDigits()));
+                    assertEquals(point, buffer.getDecimalPoint());
+                });
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/src/jdk/nashorn/internal/runtime/doubleconv/test/BignumTest.java	Wed Nov 11 15:22:14 2015 +0100
@@ -0,0 +1,1486 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// This file is available under and governed by the GNU General Public
+// License version 2 only, as published by the Free Software Foundation.
+// However, the following notice accompanied the original version of this
+// file:
+//
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package jdk.nashorn.internal.runtime.doubleconv.test;
+
+import org.testng.annotations.Test;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * Bignum class tests
+ *
+ * @test
+ * @run testng jdk.nashorn.internal.runtime.doubleconv.test.BignumTest
+ */
+@SuppressWarnings("javadoc")
+public class BignumTest {
+
+    static final Class<?> Bignum;
+    static final Constructor<?> ctor;
+
+    static {
+        try {
+            Bignum = Class.forName("jdk.nashorn.internal.runtime.doubleconv.Bignum");
+            ctor = Bignum.getDeclaredConstructor();
+            ctor.setAccessible(true);
+        } catch (final Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static Method method(final String name, final Class<?>... params) throws NoSuchMethodException {
+        final Method m = Bignum.getDeclaredMethod(name, params);
+        m.setAccessible(true);
+        return m;
+    }
+
+    @Test
+    public void testAssign() throws Exception {
+
+        Object bignum = ctor.newInstance();
+        Object bignum2 = ctor.newInstance();
+
+        final Method assignUInt16 = method("assignUInt16", char.class);
+        final Method assignUInt64 = method("assignUInt64", long.class);
+        final Method assignDecimalString = method("assignDecimalString", String.class);
+        final Method assignHexString = method("assignHexString", String.class);
+        final Method toHexString = method("toHexString");
+
+        assignUInt16.invoke(bignum, (char) 0);
+        assertEquals(toHexString.invoke(bignum), "0");
+        assignUInt16.invoke(bignum, (char) 0xA);
+        assertEquals(toHexString.invoke(bignum), "A");
+        assignUInt16.invoke(bignum, (char) 0x20);
+        assertEquals(toHexString.invoke(bignum), "20");
+
+        assignUInt64.invoke(bignum, 0);
+        assertEquals(toHexString.invoke(bignum), "0");
+        assignUInt64.invoke(bignum, 0xA);
+        assertEquals(toHexString.invoke(bignum), "A");
+        assignUInt64.invoke(bignum, 0x20);
+        assertEquals(toHexString.invoke(bignum), "20");
+        assignUInt64.invoke(bignum, 0x100);
+        assertEquals(toHexString.invoke(bignum), "100");
+
+        // The first real test, since this will not fit into one bigit.
+        assignUInt64.invoke(bignum, 0x12345678L);
+        assertEquals(toHexString.invoke(bignum), "12345678");
+
+        assignUInt64.invoke(bignum, 0xFFFFFFFFFFFFFFFFL);
+        assertEquals(toHexString.invoke(bignum), "FFFFFFFFFFFFFFFF");
+
+        assignUInt64.invoke(bignum, 0x123456789ABCDEF0L);
+        assertEquals(toHexString.invoke(bignum), "123456789ABCDEF0");
+
+        assignUInt64.invoke(bignum2, 0x123456789ABCDEF0L);
+        assertEquals(toHexString.invoke(bignum2), "123456789ABCDEF0");
+
+        assignDecimalString.invoke(bignum, "0");
+        assertEquals(toHexString.invoke(bignum), "0");
+
+        assignDecimalString.invoke(bignum, "1");
+        assertEquals(toHexString.invoke(bignum), "1");
+
+        assignDecimalString.invoke(bignum, "1234567890");
+        assertEquals(toHexString.invoke(bignum), "499602D2");
+
+        assignHexString.invoke(bignum, "0");
+        assertEquals(toHexString.invoke(bignum), "0");
+
+        assignHexString.invoke(bignum, "123456789ABCDEF0");
+        assertEquals(toHexString.invoke(bignum), "123456789ABCDEF0");
+    }
+
+    @Test
+    public void testShiftLeft() throws Exception {
+
+        final Object bignum = ctor.newInstance();
+
+        final Method assignHexString = method("assignHexString", String.class);
+        final Method shiftLeft = method("shiftLeft", int.class);
+        final Method toHexString = method("toHexString");
+
+
+        assignHexString.invoke(bignum, "0");
+        shiftLeft.invoke(bignum, 100);
+        assertEquals(toHexString.invoke(bignum), "0");
+
+        assignHexString.invoke(bignum, "1");
+        shiftLeft.invoke(bignum, 1);
+        assertEquals(toHexString.invoke(bignum), "2");
+
+        assignHexString.invoke(bignum, "1");
+        shiftLeft.invoke(bignum, 4);
+        assertEquals(toHexString.invoke(bignum), "10");
+
+        assignHexString.invoke(bignum, "1");
+        shiftLeft.invoke(bignum, 32);
+        assertEquals(toHexString.invoke(bignum), "100000000");
+
+        assignHexString.invoke(bignum, "1");
+        shiftLeft.invoke(bignum, 64);
+        assertEquals(toHexString.invoke(bignum), "10000000000000000");
+
+        assignHexString.invoke(bignum, "123456789ABCDEF");
+        shiftLeft.invoke(bignum, 64);
+        assertEquals(toHexString.invoke(bignum), "123456789ABCDEF0000000000000000");
+        shiftLeft.invoke(bignum, 1);
+        assertEquals(toHexString.invoke(bignum), "2468ACF13579BDE0000000000000000");
+    }
+
+
+
+    @Test
+    public void testAddUInt64() throws Exception {
+
+        final Object bignum = ctor.newInstance();
+
+        final Method addUInt64 = method("addUInt64", long.class);
+        final Method assignUInt16 = method("assignUInt16", char.class);
+        final Method assignHexString = method("assignHexString", String.class);
+        final Method shiftLeft = method("shiftLeft", int.class);
+        final Method toHexString = method("toHexString");
+
+        assignHexString.invoke(bignum, "0");
+        addUInt64.invoke(bignum, 0xA);
+        assertEquals(toHexString.invoke(bignum), "A");
+
+        assignHexString.invoke(bignum, "1");
+        addUInt64.invoke(bignum, 0xA);
+        assertEquals(toHexString.invoke(bignum), "B");
+
+        assignHexString.invoke(bignum, "1");
+        addUInt64.invoke(bignum, 0x100);
+        assertEquals(toHexString.invoke(bignum), "101");
+
+        assignHexString.invoke(bignum, "1");
+        addUInt64.invoke(bignum, 0xFFFF);
+        assertEquals(toHexString.invoke(bignum), "10000");
+
+        assignHexString.invoke(bignum, "FFFFFFF");
+        addUInt64.invoke(bignum, 0x1);
+        assertEquals(toHexString.invoke(bignum), "10000000");
+
+        assignHexString.invoke(bignum, "10000000000000000000000000000000000000000000");
+        addUInt64.invoke(bignum, 0xFFFF);
+        assertEquals(toHexString.invoke(bignum), "1000000000000000000000000000000000000000FFFF");
+
+        assignHexString.invoke(bignum, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
+        addUInt64.invoke(bignum, 0x1);
+        assertEquals(toHexString.invoke(bignum), "100000000000000000000000000000000000000000000");
+
+        assignHexString.invoke(bignum, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
+        addUInt64.invoke(bignum, 0x1);
+        assertEquals(toHexString.invoke(bignum), "100000000000000000000000000000000000000000000");
+
+        assignUInt16.invoke(bignum, (char) 0x1);
+        shiftLeft.invoke(bignum, 100);
+        addUInt64.invoke(bignum, 1);
+        assertEquals(toHexString.invoke(bignum), "10000000000000000000000001");
+
+        assignUInt16.invoke(bignum, (char) 0x1);
+        shiftLeft.invoke(bignum, 100);
+        addUInt64.invoke(bignum, 0xFFFF);
+        assertEquals(toHexString.invoke(bignum), "1000000000000000000000FFFF");
+
+        assignHexString.invoke(bignum, "0");
+        addUInt64.invoke(bignum, 0xA00000000L);
+        assertEquals(toHexString.invoke(bignum), "A00000000");
+
+        assignHexString.invoke(bignum, "1");
+        addUInt64.invoke(bignum, 0xA00000000L);
+        assertEquals(toHexString.invoke(bignum), "A00000001");
+
+        assignHexString.invoke(bignum, "1");
+        addUInt64.invoke(bignum, 0x10000000000L);
+        assertEquals(toHexString.invoke(bignum), "10000000001");
+
+        assignHexString.invoke(bignum, "1");
+        addUInt64.invoke(bignum, 0xFFFF00000000L);
+        assertEquals(toHexString.invoke(bignum), "FFFF00000001");
+
+        assignHexString.invoke(bignum, "FFFFFFF");
+        addUInt64.invoke(bignum, 0x100000000L);
+        assertEquals(toHexString.invoke(bignum), "10FFFFFFF");
+
+        assignHexString.invoke(bignum, "10000000000000000000000000000000000000000000");
+        addUInt64.invoke(bignum, 0xFFFF00000000L);
+        assertEquals(toHexString.invoke(bignum), "10000000000000000000000000000000FFFF00000000");
+
+        assignHexString.invoke(bignum, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
+        addUInt64.invoke(bignum, 0x100000000L);
+        assertEquals(toHexString.invoke(bignum), "1000000000000000000000000000000000000FFFFFFFF");
+
+        assignUInt16.invoke(bignum, (char) 0x1);
+        shiftLeft.invoke(bignum, 100);
+        addUInt64.invoke(bignum, 0x100000000L);
+        assertEquals(toHexString.invoke(bignum), "10000000000000000100000000");
+
+        assignUInt16.invoke(bignum, (char) 0x1);
+        shiftLeft.invoke(bignum, 100);
+        addUInt64.invoke(bignum, 0xFFFF00000000L);
+        assertEquals(toHexString.invoke(bignum), "10000000000000FFFF00000000");
+    }
+
+    @Test
+    public void testAddBignum() throws Exception {
+
+        final Object bignum = ctor.newInstance();
+        final Object other = ctor.newInstance();
+
+        final Method addBignum = method("addBignum", Bignum);
+        final Method assignUInt16 = method("assignUInt16", char.class);
+        final Method assignHexString = method("assignHexString", String.class);
+        final Method shiftLeft = method("shiftLeft", int.class);
+        final Method toHexString = method("toHexString");
+
+        assignHexString.invoke(other, "1");
+        assignHexString.invoke(bignum, "0");
+        addBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "1");
+
+        assignHexString.invoke(bignum, "1");
+        addBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "2");
+
+        assignHexString.invoke(bignum, "FFFFFFF");
+        addBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "10000000");
+
+        assignHexString.invoke(bignum, "FFFFFFFFFFFFFF");
+        addBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "100000000000000");
+
+        assignHexString.invoke(bignum, "10000000000000000000000000000000000000000000");
+        addBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "10000000000000000000000000000000000000000001");
+
+        assignHexString.invoke(other, "1000000000000");
+
+        assignHexString.invoke(bignum, "1");
+        addBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "1000000000001");
+
+        assignHexString.invoke(bignum, "FFFFFFF");
+        addBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "100000FFFFFFF");
+
+        assignHexString.invoke(bignum, "10000000000000000000000000000000000000000000");
+        addBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "10000000000000000000000000000001000000000000");
+
+        assignHexString.invoke(bignum, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
+        addBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "1000000000000000000000000000000FFFFFFFFFFFF");
+
+        assignUInt16.invoke(bignum, (char) 0x1);
+        shiftLeft.invoke(bignum, 100);
+        addBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "10000000000001000000000000");
+
+        shiftLeft.invoke(other, 64);
+        // other == "10000000000000000000000000000"
+
+        assignUInt16.invoke(bignum, (char) 0x1);
+        addBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "10000000000000000000000000001");
+
+        assignHexString.invoke(bignum, "FFFFFFF");
+        addBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "1000000000000000000000FFFFFFF");
+
+        assignHexString.invoke(bignum, "10000000000000000000000000000000000000000000");
+        addBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "10000000000000010000000000000000000000000000");
+
+        assignHexString.invoke(bignum, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
+        addBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "100000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFF");
+
+        assignUInt16.invoke(bignum, (char) 0x1);
+        shiftLeft.invoke(bignum, 100);
+        addBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "10010000000000000000000000000");
+    }
+
+
+    @Test
+    public void testSubtractBignum() throws Exception {
+
+        final Object bignum = ctor.newInstance();
+        final Object other = ctor.newInstance();
+
+        final Method assignUInt16 = method("assignUInt16", char.class);
+        final Method assignHexString = method("assignHexString", String.class);
+        final Method shiftLeft = method("shiftLeft", int.class);
+        final Method subtractBignum = method("subtractBignum", Bignum);
+
+        final Method toHexString = method("toHexString");
+
+        assignHexString.invoke(bignum, "1");
+        assignHexString.invoke(other, "0");
+        subtractBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "1");
+
+        assignHexString.invoke(bignum, "2");
+        assignHexString.invoke(other, "0");
+        subtractBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "2");
+
+        assignHexString.invoke(bignum, "10000000");
+        assignHexString.invoke(other, "1");
+        subtractBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "FFFFFFF");
+
+        assignHexString.invoke(bignum, "100000000000000");
+        assignHexString.invoke(other, "1");
+        subtractBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "FFFFFFFFFFFFFF");
+
+        assignHexString.invoke(bignum, "10000000000000000000000000000000000000000001");
+        assignHexString.invoke(other, "1");
+        subtractBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "10000000000000000000000000000000000000000000");
+
+        assignHexString.invoke(bignum, "1000000000001");
+        assignHexString.invoke(other, "1000000000000");
+        subtractBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "1");
+
+        assignHexString.invoke(bignum, "100000FFFFFFF");
+        assignHexString.invoke(other, "1000000000000");
+        subtractBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "FFFFFFF");
+
+        assignHexString.invoke(bignum, "10000000000000000000000000000001000000000000");
+        assignHexString.invoke(other, "1000000000000");
+        subtractBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "10000000000000000000000000000000000000000000");
+
+        assignHexString.invoke(bignum, "1000000000000000000000000000000FFFFFFFFFFFF");
+        assignHexString.invoke(other, "1000000000000");
+        subtractBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
+
+        assignUInt16.invoke(bignum, (char) 0x1);
+        shiftLeft.invoke(bignum, 100);
+        // "10 0000 0000 0000 0000 0000 0000"
+        assignHexString.invoke(other, "1000000000000");
+        subtractBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "FFFFFFFFFFFFF000000000000");
+
+        assignHexString.invoke(other, "1000000000000");
+        shiftLeft.invoke(other, 48);
+        // other == "1000000000000000000000000"
+
+        assignUInt16.invoke(bignum, (char) 0x1);
+        shiftLeft.invoke(bignum, 100);
+        // bignum == "10000000000000000000000000"
+        subtractBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "F000000000000000000000000");
+
+        assignUInt16.invoke(other, (char) 0x1);
+        shiftLeft.invoke(other, 35);
+        // other == "800000000"
+        assignHexString.invoke(bignum, "FFFFFFF");
+        shiftLeft.invoke(bignum, 60);
+        // bignum = FFFFFFF000000000000000
+        subtractBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "FFFFFFEFFFFFF800000000");
+
+        assignHexString.invoke(bignum, "10000000000000000000000000000000000000000000");
+        subtractBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF800000000");
+
+        assignHexString.invoke(bignum, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
+        subtractBignum.invoke(bignum, other);
+        assertEquals(toHexString.invoke(bignum), "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFF");
+    }
+
+
+    @Test
+    public void testMultiplyUInt32() throws Exception {
+
+        final Object bignum = ctor.newInstance();
+
+        final Method assignHexString = method("assignHexString", String.class);
+        final Method assignDecimalString = method("assignDecimalString", String.class);
+        final Method assignUInt16 = method("assignUInt16", char.class);
+        final Method multiplyByUInt32 = method("multiplyByUInt32", int.class);
+        final Method shiftLeft = method("shiftLeft", int.class);
+        final Method toHexString = method("toHexString");
+
+        assignHexString.invoke(bignum, "0");
+        multiplyByUInt32.invoke(bignum, 0x25);
+        assertEquals(toHexString.invoke(bignum), "0");
+
+        assignHexString.invoke(bignum, "2");
+        multiplyByUInt32.invoke(bignum, 0x5);
+        assertEquals(toHexString.invoke(bignum), "A");
+
+        assignHexString.invoke(bignum, "10000000");
+        multiplyByUInt32.invoke(bignum, 0x9);
+        assertEquals(toHexString.invoke(bignum), "90000000");
+
+        assignHexString.invoke(bignum, "100000000000000");
+        multiplyByUInt32.invoke(bignum, 0xFFFF);
+        assertEquals(toHexString.invoke(bignum), "FFFF00000000000000");
+
+        assignHexString.invoke(bignum, "100000000000000");
+        multiplyByUInt32.invoke(bignum, 0xFFFFFFFF);
+        assertEquals(toHexString.invoke(bignum), "FFFFFFFF00000000000000");
+
+        assignHexString.invoke(bignum, "1234567ABCD");
+        multiplyByUInt32.invoke(bignum, 0xFFF);
+        assertEquals(toHexString.invoke(bignum), "12333335552433");
+
+        assignHexString.invoke(bignum, "1234567ABCD");
+        multiplyByUInt32.invoke(bignum, 0xFFFFFFF);
+        assertEquals(toHexString.invoke(bignum), "12345679998A985433");
+
+
+        assignHexString.invoke(bignum, "FFFFFFFFFFFFFFFF");
+        multiplyByUInt32.invoke(bignum, 0x2);
+        assertEquals(toHexString.invoke(bignum), "1FFFFFFFFFFFFFFFE");
+
+        assignHexString.invoke(bignum, "FFFFFFFFFFFFFFFF");
+        multiplyByUInt32.invoke(bignum, 0x4);
+        assertEquals(toHexString.invoke(bignum), "3FFFFFFFFFFFFFFFC");
+
+        assignHexString.invoke(bignum, "FFFFFFFFFFFFFFFF");
+        multiplyByUInt32.invoke(bignum, 0xF);
+        assertEquals(toHexString.invoke(bignum), "EFFFFFFFFFFFFFFF1");
+
+        assignHexString.invoke(bignum, "FFFFFFFFFFFFFFFF");
+        multiplyByUInt32.invoke(bignum, 0xFFFFFF);
+        assertEquals(toHexString.invoke(bignum), "FFFFFEFFFFFFFFFF000001");
+
+        assignUInt16.invoke(bignum, (char) 0x1);
+        shiftLeft.invoke(bignum, 100);
+        // "10 0000 0000 0000 0000 0000 0000"
+        multiplyByUInt32.invoke(bignum, 2);
+        assertEquals(toHexString.invoke(bignum), "20000000000000000000000000");
+
+        assignUInt16.invoke(bignum, (char) 0x1);
+        shiftLeft.invoke(bignum, 100);
+        // "10 0000 0000 0000 0000 0000 0000"
+        multiplyByUInt32.invoke(bignum, 0xF);
+        assertEquals(toHexString.invoke(bignum), "F0000000000000000000000000");
+
+        assignUInt16.invoke(bignum, (char) 0xFFFF);
+        shiftLeft.invoke(bignum, 100);
+        // "FFFF0 0000 0000 0000 0000 0000 0000"
+        multiplyByUInt32.invoke(bignum, 0xFFFF);
+        assertEquals(toHexString.invoke(bignum), "FFFE00010000000000000000000000000");
+
+        assignUInt16.invoke(bignum, (char) 0xFFFF);
+        shiftLeft.invoke(bignum, 100);
+        // "FFFF0 0000 0000 0000 0000 0000 0000"
+        multiplyByUInt32.invoke(bignum, 0xFFFFFFFF);
+        assertEquals(toHexString.invoke(bignum), "FFFEFFFF00010000000000000000000000000");
+
+        assignUInt16.invoke(bignum, (char) 0xFFFF);
+        shiftLeft.invoke(bignum, 100);
+        // "FFFF0 0000 0000 0000 0000 0000 0000"
+        multiplyByUInt32.invoke(bignum, 0xFFFFFFFF);
+        assertEquals(toHexString.invoke(bignum), "FFFEFFFF00010000000000000000000000000");
+
+        assignDecimalString.invoke(bignum, "15611230384529777");
+        multiplyByUInt32.invoke(bignum, 10000000);
+        assertEquals(toHexString.invoke(bignum), "210EDD6D4CDD2580EE80");
+    }
+
+
+
+    @Test
+    public void testMultiplyUInt64() throws Exception {
+
+        final Object bignum = ctor.newInstance();
+
+        final Method assignUInt16 = method("assignUInt16", char.class);
+        final Method assignDecimalString = method("assignDecimalString", String.class);
+        final Method assignHexString = method("assignHexString", String.class);
+        final Method multiplyByUInt64 = method("multiplyByUInt64", long.class);
+        final Method shiftLeft = method("shiftLeft", int.class);
+        final Method toHexString = method("toHexString");
+
+        assignHexString.invoke(bignum, "0");
+        multiplyByUInt64.invoke(bignum, 0x25);
+        assertEquals(toHexString.invoke(bignum), "0");
+
+        assignHexString.invoke(bignum, "2");
+        multiplyByUInt64.invoke(bignum, 0x5);
+        assertEquals(toHexString.invoke(bignum), "A");
+
+        assignHexString.invoke(bignum, "10000000");
+        multiplyByUInt64.invoke(bignum, 0x9);
+        assertEquals(toHexString.invoke(bignum), "90000000");
+
+        assignHexString.invoke(bignum, "100000000000000");
+        multiplyByUInt64.invoke(bignum, 0xFFFF);
+        assertEquals(toHexString.invoke(bignum), "FFFF00000000000000");
+
+        assignHexString.invoke(bignum, "100000000000000");
+        multiplyByUInt64.invoke(bignum, 0xFFFFFFFFFFFFFFFFL);
+        assertEquals(toHexString.invoke(bignum), "FFFFFFFFFFFFFFFF00000000000000");
+
+        assignHexString.invoke(bignum, "1234567ABCD");
+        multiplyByUInt64.invoke(bignum, 0xFFF);
+        assertEquals(toHexString.invoke(bignum), "12333335552433");
+
+        assignHexString.invoke(bignum, "1234567ABCD");
+        multiplyByUInt64.invoke(bignum, 0xFFFFFFFFFFL);
+        assertEquals(toHexString.invoke(bignum), "1234567ABCBDCBA985433");
+
+        assignHexString.invoke(bignum, "FFFFFFFFFFFFFFFF");
+        multiplyByUInt64.invoke(bignum, 0x2);
+        assertEquals(toHexString.invoke(bignum), "1FFFFFFFFFFFFFFFE");
+
+        assignHexString.invoke(bignum, "FFFFFFFFFFFFFFFF");
+        multiplyByUInt64.invoke(bignum, 0x4);
+        assertEquals(toHexString.invoke(bignum), "3FFFFFFFFFFFFFFFC");
+
+        assignHexString.invoke(bignum, "FFFFFFFFFFFFFFFF");
+        multiplyByUInt64.invoke(bignum, 0xF);
+        assertEquals(toHexString.invoke(bignum), "EFFFFFFFFFFFFFFF1");
+
+        assignHexString.invoke(bignum, "FFFFFFFFFFFFFFFF");
+        multiplyByUInt64.invoke(bignum, 0xFFFFFFFFFFFFFFFFL);
+        assertEquals(toHexString.invoke(bignum), "FFFFFFFFFFFFFFFE0000000000000001");
+
+        assignUInt16.invoke(bignum, (char) 0x1);
+        shiftLeft.invoke(bignum, 100);
+        // "10 0000 0000 0000 0000 0000 0000"
+        multiplyByUInt64.invoke(bignum, 2);
+        assertEquals(toHexString.invoke(bignum), "20000000000000000000000000");
+
+        assignUInt16.invoke(bignum, (char) 0x1);
+        shiftLeft.invoke(bignum, 100);
+        // "10 0000 0000 0000 0000 0000 0000"
+        multiplyByUInt64.invoke(bignum, 0xF);
+        assertEquals(toHexString.invoke(bignum), "F0000000000000000000000000");
+
+        assignUInt16.invoke(bignum, (char) 0xFFFF);
+        shiftLeft.invoke(bignum, 100);
+        // "FFFF0 0000 0000 0000 0000 0000 0000"
+        multiplyByUInt64.invoke(bignum, 0xFFFF);
+        assertEquals(toHexString.invoke(bignum), "FFFE00010000000000000000000000000");
+
+        assignUInt16.invoke(bignum, (char) 0xFFFF);
+        shiftLeft.invoke(bignum, 100);
+        // "FFFF0 0000 0000 0000 0000 0000 0000"
+        multiplyByUInt64.invoke(bignum, 0xFFFFFFFFL);
+        assertEquals(toHexString.invoke(bignum), "FFFEFFFF00010000000000000000000000000");
+
+        assignUInt16.invoke(bignum, (char) 0xFFFF);
+        shiftLeft.invoke(bignum, 100);
+        // "FFFF0 0000 0000 0000 0000 0000 0000"
+        multiplyByUInt64.invoke(bignum, 0xFFFFFFFFFFFFFFFFL);
+        assertEquals(toHexString.invoke(bignum), "FFFEFFFFFFFFFFFF00010000000000000000000000000");
+
+        assignDecimalString.invoke(bignum, "15611230384529777");
+        multiplyByUInt64.invoke(bignum, 0x8ac7230489e80000L);
+        assertEquals(toHexString.invoke(bignum), "1E10EE4B11D15A7F3DE7F3C7680000");
+    }
+
+    @Test
+    public void testMultiplyPowerOfTen() throws Exception {
+
+        final Object bignum = ctor.newInstance();
+        final Object bignum2 = ctor.newInstance();
+
+        final Method assignBignum = method("assignBignum", Bignum);
+        final Method assignDecimalString = method("assignDecimalString", String.class);
+        final Method assignHexString = method("assignHexString", String.class);
+        final Method multiplyByPowerOfTen = method("multiplyByPowerOfTen", int.class);
+        final Method toHexString = method("toHexString");
+
+        assignDecimalString.invoke(bignum, "1234");
+        multiplyByPowerOfTen.invoke(bignum, 1);
+        assertEquals(toHexString.invoke(bignum), "3034");
+
+        assignDecimalString.invoke(bignum, "1234");
+        multiplyByPowerOfTen.invoke(bignum, 2);
+        assertEquals(toHexString.invoke(bignum), "1E208");
+
+        assignDecimalString.invoke(bignum, "1234");
+        multiplyByPowerOfTen.invoke(bignum, 3);
+        assertEquals(toHexString.invoke(bignum), "12D450");
+
+        assignDecimalString.invoke(bignum, "1234");
+        multiplyByPowerOfTen.invoke(bignum, 4);
+        assertEquals(toHexString.invoke(bignum), "BC4B20");
+
+        assignDecimalString.invoke(bignum, "1234");
+        multiplyByPowerOfTen.invoke(bignum, 5);
+        assertEquals(toHexString.invoke(bignum), "75AEF40");
+
+        assignDecimalString.invoke(bignum, "1234");
+        multiplyByPowerOfTen.invoke(bignum, 6);
+        assertEquals(toHexString.invoke(bignum), "498D5880");
+
+        assignDecimalString.invoke(bignum, "1234");
+        multiplyByPowerOfTen.invoke(bignum, 7);
+        assertEquals(toHexString.invoke(bignum), "2DF857500");
+
+        assignDecimalString.invoke(bignum, "1234");
+        multiplyByPowerOfTen.invoke(bignum, 8);
+        assertEquals(toHexString.invoke(bignum), "1CBB369200");
+
+        assignDecimalString.invoke(bignum, "1234");
+        multiplyByPowerOfTen.invoke(bignum, 9);
+        assertEquals(toHexString.invoke(bignum), "11F5021B400");
+
+        assignDecimalString.invoke(bignum, "1234");
+        multiplyByPowerOfTen.invoke(bignum, 10);
+        assertEquals(toHexString.invoke(bignum), "B3921510800");
+
+        assignDecimalString.invoke(bignum, "1234");
+        multiplyByPowerOfTen.invoke(bignum, 11);
+        assertEquals(toHexString.invoke(bignum), "703B4D2A5000");
+
+        assignDecimalString.invoke(bignum, "1234");
+        multiplyByPowerOfTen.invoke(bignum, 12);
+        assertEquals(toHexString.invoke(bignum), "4625103A72000");
+
+        assignDecimalString.invoke(bignum, "1234");
+        multiplyByPowerOfTen.invoke(bignum, 13);
+        assertEquals(toHexString.invoke(bignum), "2BD72A24874000");
+
+        assignDecimalString.invoke(bignum, "1234");
+        multiplyByPowerOfTen.invoke(bignum, 14);
+        assertEquals(toHexString.invoke(bignum), "1B667A56D488000");
+
+        assignDecimalString.invoke(bignum, "1234");
+        multiplyByPowerOfTen.invoke(bignum, 15);
+        assertEquals(toHexString.invoke(bignum), "11200C7644D50000");
+
+        assignDecimalString.invoke(bignum, "1234");
+        multiplyByPowerOfTen.invoke(bignum, 16);
+        assertEquals(toHexString.invoke(bignum), "AB407C9EB0520000");
+
+        assignDecimalString.invoke(bignum, "1234");
+        multiplyByPowerOfTen.invoke(bignum, 17);
+        assertEquals(toHexString.invoke(bignum), "6B084DE32E3340000");
+
+        assignDecimalString.invoke(bignum, "1234");
+        multiplyByPowerOfTen.invoke(bignum, 18);
+        assertEquals(toHexString.invoke(bignum), "42E530ADFCE0080000");
+
+        assignDecimalString.invoke(bignum, "1234");
+        multiplyByPowerOfTen.invoke(bignum, 19);
+        assertEquals(toHexString.invoke(bignum), "29CF3E6CBE0C0500000");
+
+        assignDecimalString.invoke(bignum, "1234");
+        multiplyByPowerOfTen.invoke(bignum, 20);
+        assertEquals(toHexString.invoke(bignum), "1A218703F6C783200000");
+
+        assignDecimalString.invoke(bignum, "1234");
+        multiplyByPowerOfTen.invoke(bignum, 21);
+        assertEquals(toHexString.invoke(bignum), "1054F4627A3CB1F400000");
+
+        assignDecimalString.invoke(bignum, "1234");
+        multiplyByPowerOfTen.invoke(bignum, 22);
+        assertEquals(toHexString.invoke(bignum), "A3518BD8C65EF38800000");
+
+        assignDecimalString.invoke(bignum, "1234");
+        multiplyByPowerOfTen.invoke(bignum, 23);
+        assertEquals(toHexString.invoke(bignum), "6612F7677BFB5835000000");
+
+        assignDecimalString.invoke(bignum, "1234");
+        multiplyByPowerOfTen.invoke(bignum, 24);
+        assertEquals(toHexString.invoke(bignum), "3FCBDAA0AD7D17212000000");
+
+        assignDecimalString.invoke(bignum, "1234");
+        multiplyByPowerOfTen.invoke(bignum, 25);
+        assertEquals(toHexString.invoke(bignum), "27DF68A46C6E2E74B4000000");
+
+        assignDecimalString.invoke(bignum, "1234");
+        multiplyByPowerOfTen.invoke(bignum, 26);
+        assertEquals(toHexString.invoke(bignum), "18EBA166C3C4DD08F08000000");
+
+        assignDecimalString.invoke(bignum, "1234");
+        multiplyByPowerOfTen.invoke(bignum, 27);
+        assertEquals(toHexString.invoke(bignum), "F9344E03A5B0A259650000000");
+
+        assignDecimalString.invoke(bignum, "1234");
+        multiplyByPowerOfTen.invoke(bignum, 28);
+        assertEquals(toHexString.invoke(bignum), "9BC0B0C2478E6577DF20000000");
+
+        assignDecimalString.invoke(bignum, "1234");
+        multiplyByPowerOfTen.invoke(bignum, 29);
+        assertEquals(toHexString.invoke(bignum), "61586E796CB8FF6AEB740000000");
+
+        assignDecimalString.invoke(bignum, "1234");
+        multiplyByPowerOfTen.invoke(bignum, 30);
+        assertEquals(toHexString.invoke(bignum), "3CD7450BE3F39FA2D32880000000");
+
+        assignDecimalString.invoke(bignum, "1234");
+        multiplyByPowerOfTen.invoke(bignum, 31);
+        assertEquals(toHexString.invoke(bignum), "26068B276E7843C5C3F9500000000");
+
+        assignDecimalString.invoke(bignum, "1234");
+        multiplyByPowerOfTen.invoke(bignum, 50);
+        assertEquals(toHexString.invoke(bignum), "149D1B4CFED03B23AB5F4E1196EF45C08000000000000");
+
+        assignDecimalString.invoke(bignum, "1234");
+        multiplyByPowerOfTen.invoke(bignum, 100);
+        assertEquals(toHexString.invoke(bignum),
+                "5827249F27165024FBC47DFCA9359BF316332D1B91ACEECF471FBAB06D9B2" +
+                "0000000000000000000000000");
+
+        assignDecimalString.invoke(bignum, "1234");
+        multiplyByPowerOfTen.invoke(bignum, 200);
+        assertEquals(toHexString.invoke(bignum),
+                "64C1F5C06C3816AFBF8DAFD5A3D756365BB0FD020E6F084E759C1F7C99E4F" +
+                "55B9ACC667CEC477EB958C2AEEB3C6C19BA35A1AD30B35C51EB72040920000" +
+                "0000000000000000000000000000000000000000000000");
+
+        assignDecimalString.invoke(bignum, "1234");
+        multiplyByPowerOfTen.invoke(bignum, 500);
+        assertEquals(toHexString.invoke(bignum),
+                "96741A625EB5D7C91039FEB5C5ACD6D9831EDA5B083D800E6019442C8C8223" +
+                "3EAFB3501FE2058062221E15121334928880827DEE1EC337A8B26489F3A40A" +
+                "CB440A2423734472D10BFCE886F41B3AF9F9503013D86D088929CA86EEB4D8" +
+                "B9C831D0BD53327B994A0326227CFD0ECBF2EB48B02387AAE2D4CCCDF1F1A1" +
+                "B8CC4F1FA2C56AD40D0E4DAA9C28CDBF0A549098EA13200000000000000000" +
+                "00000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000");
+
+        assignDecimalString.invoke(bignum, "1234");
+        multiplyByPowerOfTen.invoke(bignum, 1000);
+        assertEquals(toHexString.invoke(bignum),
+                "1258040F99B1CD1CC9819C676D413EA50E4A6A8F114BB0C65418C62D399B81" +
+                "6361466CA8E095193E1EE97173553597C96673AF67FAFE27A66E7EF2E5EF2E" +
+                "E3F5F5070CC17FE83BA53D40A66A666A02F9E00B0E11328D2224B8694C7372" +
+                "F3D536A0AD1985911BD361496F268E8B23112500EAF9B88A9BC67B2AB04D38" +
+                "7FEFACD00F5AF4F764F9ABC3ABCDE54612DE38CD90CB6647CA389EA0E86B16" +
+                "BF7A1F34086E05ADBE00BD1673BE00FAC4B34AF1091E8AD50BA675E0381440" +
+                "EA8E9D93E75D816BAB37C9844B1441C38FC65CF30ABB71B36433AF26DD97BD" +
+                "ABBA96C03B4919B8F3515B92826B85462833380DC193D79F69D20DD6038C99" +
+                "6114EF6C446F0BA28CC772ACBA58B81C04F8FFDE7B18C4E5A3ABC51E637FDF" +
+                "6E37FDFF04C940919390F4FF92000000000000000000000000000000000000" +
+                "00000000000000000000000000000000000000000000000000000000000000" +
+                "00000000000000000000000000000000000000000000000000000000000000" +
+                "00000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000");
+
+        assignHexString.invoke(bignum2,
+                "3DA774C07FB5DF54284D09C675A492165B830D5DAAEB2A7501" +
+                "DA17CF9DFA1CA2282269F92A25A97314296B717E3DCBB9FE17" +
+                "41A842FE2913F540F40796F2381155763502C58B15AF7A7F88" +
+                "6F744C9164FF409A28F7FA0C41F89ED79C1BE9F322C8578B97" +
+                "841F1CBAA17D901BE1230E3C00E1C643AF32638B5674E01FEA" +
+                "96FC90864E621B856A9E1CE56E6EB545B9C2F8F0CC10DDA88D" +
+                "CC6D282605F8DB67044F2DFD3695E7BA63877AE16701536AE6" +
+                "567C794D0BFE338DFBB42D92D4215AF3BB22BF0A8B283FDDC2" +
+                "C667A10958EA6D2");
+        assertEquals(toHexString.invoke(bignum2),
+                "3DA774C07FB5DF54284D09C675A492165B830D5DAAEB2A7501" +
+                "DA17CF9DFA1CA2282269F92A25A97314296B717E3DCBB9FE17" +
+                "41A842FE2913F540F40796F2381155763502C58B15AF7A7F88" +
+                "6F744C9164FF409A28F7FA0C41F89ED79C1BE9F322C8578B97" +
+                "841F1CBAA17D901BE1230E3C00E1C643AF32638B5674E01FEA" +
+                "96FC90864E621B856A9E1CE56E6EB545B9C2F8F0CC10DDA88D" +
+                "CC6D282605F8DB67044F2DFD3695E7BA63877AE16701536AE6" +
+                "567C794D0BFE338DFBB42D92D4215AF3BB22BF0A8B283FDDC2" +
+                "C667A10958EA6D2");
+
+        assignBignum.invoke(bignum, bignum2);
+        multiplyByPowerOfTen.invoke(bignum, 1);
+
+        assertEquals(toHexString.invoke(bignum),
+                "2688A8F84FD1AB949930261C0986DB4DF931E85A8AD2FA8921284EE1C2BC51" +
+                "E55915823BBA5789E7EC99E326EEE69F543ECE890929DED9AC79489884BE57" +
+                "630AD569E121BB76ED8DAC8FB545A8AFDADF1F8860599AFC47A93B6346C191" +
+                "7237F5BD36B73EB29371F4A4EE7A116CB5E8E5808D1BEA4D7F7E3716090C13" +
+                "F29E5DDA53F0FD513362A2D20F6505314B9419DB967F8A8A89589FC43917C3" +
+                "BB892062B17CBE421DB0D47E34ACCCE060D422CFF60DCBD0277EE038BD509C" +
+                "7BC494D8D854F5B76696F927EA99BC00C4A5D7928434");
+
+        assignBignum.invoke(bignum, bignum2);
+        multiplyByPowerOfTen.invoke(bignum, 2);
+
+        assertEquals(toHexString.invoke(bignum),
+                "1815699B31E30B3CDFBE17D185F44910BBBF313896C3DC95B4B9314D19B5B32" +
+                "F57AD71655476B630F3E02DF855502394A74115A5BA2B480BCBCD5F52F6F69D" +
+                "E6C5622CB5152A54788BD9D14B896DE8CB73B53C3800DDACC9C51E0C38FAE76" +
+                "2F9964232872F9C2738E7150C4AE3F1B18F70583172706FAEE26DC5A78C77A2" +
+                "FAA874769E52C01DA5C3499F233ECF3C90293E0FB69695D763DAA3AEDA5535B" +
+                "43DAEEDF6E9528E84CEE0EC000C3C8495C1F9C89F6218AF4C23765261CD5ADD" +
+                "0787351992A01E5BB8F2A015807AE7A6BB92A08");
+
+        assignBignum.invoke(bignum, bignum2);
+        multiplyByPowerOfTen.invoke(bignum, 5);
+
+        assertEquals(toHexString.invoke(bignum),
+                "5E13A4863ADEE3E5C9FE8D0A73423D695D62D8450CED15A8C9F368952C6DC3" +
+                "F0EE7D82F3D1EFB7AF38A3B3920D410AFCAD563C8F5F39116E141A3C5C14B3" +
+                "58CD73077EA35AAD59F6E24AD98F10D5555ABBFBF33AC361EAF429FD5FBE94" +
+                "17DA9EF2F2956011F9F93646AA38048A681D984ED88127073443247CCC167C" +
+                "B354A32206EF5A733E73CF82D795A1AD598493211A6D613C39515E0E0F6304" +
+                "DCD9C810F3518C7F6A7CB6C81E99E02FCC65E8FDB7B7AE97306CC16A8631CE" +
+                "0A2AEF6568276BE4C176964A73C153FDE018E34CB4C2F40");
+
+        assignBignum.invoke(bignum, bignum2);
+        multiplyByPowerOfTen.invoke(bignum, 10);
+
+        assertEquals(toHexString.invoke(bignum),
+                "8F8CB8EB51945A7E815809F6121EF2F4E61EF3405CD9432CAD2709749EEAFD" +
+                "1B81E843F14A3667A7BDCCC9E0BB795F63CDFDB62844AC7438976C885A0116" +
+                "29607DA54F9C023CC366570B7637ED0F855D931752038A614922D0923E382C" +
+                "B8E5F6C975672DB76E0DE471937BB9EDB11E28874F1C122D5E1EF38CECE9D0" +
+                "0723056BCBD4F964192B76830634B1D322B7EB0062F3267E84F5C824343A77" +
+                "4B7DCEE6DD464F01EBDC8C671BB18BB4EF4300A42474A6C77243F2A12B03BF" +
+                "0443C38A1C0D2701EDB393135AE0DEC94211F9D4EB51F990800");
+
+        assignBignum.invoke(bignum, bignum2);
+        multiplyByPowerOfTen.invoke(bignum, 50);
+
+        assertEquals(toHexString.invoke(bignum),
+                "107A8BE345E24407372FC1DE442CBA696BC23C4FFD5B4BDFD9E5C39559815" +
+                "86628CF8472D2D589F2FC2BAD6E0816EC72CBF85CCA663D8A1EC6C51076D8" +
+                "2D247E6C26811B7EC4D4300FB1F91028DCB7B2C4E7A60C151161AA7E65E79" +
+                "B40917B12B2B5FBE7745984D4E8EFA31F9AE6062427B068B144A9CB155873" +
+                "E7C0C9F0115E5AC72DC5A73C4796DB970BF9205AB8C77A6996EB1B417F9D1" +
+                "6232431E6313C392203601B9C22CC10DDA88DCC6D282605F8DB67044F2DFD" +
+                "3695E7BA63877AE16701536AE6567C794D0BFE338DFBB42D924CF964BD2C0" +
+                "F586E03A2FCD35A408000000000000");
+
+        assignBignum.invoke(bignum, bignum2);
+        multiplyByPowerOfTen.invoke(bignum, 100);
+
+        assertEquals(toHexString.invoke(bignum),
+                "46784A90ACD0ED3E7759CC585FB32D36EB6034A6F78D92604E3BAA5ED3D8B" +
+                "6E60E854439BE448897FB4B7EA5A3D873AA0FCB3CFFD80D0530880E45F511" +
+                "722A50CE7E058B5A6F5464DB7500E34984EE3202A9441F44FA1554C0CEA96" +
+                "B438A36F25E7C9D56D71AE2CD313EC37534DA299AC0854FC48591A7CF3171" +
+                "31265AA4AE62DE32344CE7BEEEF894AE686A2DAAFE5D6D9A10971FFD9C064" +
+                "5079B209E1048F58B5192D41D84336AC4C8C489EEF00939CFC9D55C122036" +
+                "01B9C22CC10DDA88DCC6D282605F8DB67044F2DFD3695E7BA3F67B96D3A32" +
+                "E11FB5561B68744C4035B0800DC166D49D98E3FD1D5BB2000000000000000" +
+                "0000000000");
+
+        assignBignum.invoke(bignum, bignum2);
+        multiplyByPowerOfTen.invoke(bignum, 200);
+
+        assertEquals(toHexString.invoke(bignum),
+                "508BD351221DF139D72D88CDC0416845A53EE2D0E6B98352509A9AC312F8C" +
+                "6CB1A144889416201E0B6CE66EA3EBE259B5FD79ECFC1FD77963CE516CC7E" +
+                "2FE73D4B5B710C19F6BCB092C7A2FD76286543B8DBD2C596DFF2C896720BA" +
+                "DFF7BC9C366ACEA3A880AEC287C5E6207DF2739B5326FC19D773BD830B109" +
+                "ED36C7086544BF8FDB9D4B73719C2B5BC2F571A5937EC46876CD428281F6B" +
+                "F287E1E07F25C1B1D46BC37324FF657A8B2E0071DB83B86123CA34004F406" +
+                "001082D7945E90C6E8C9A9FEC2B44BE0DDA46E9F52B152E4D1336D2FCFBC9" +
+                "96E30CA0082256737365158FE36482AA7EB9DAF2AB128F10E7551A3CD5BE6" +
+                "0A922F3A7D5EED38B634A7EC95BCF7021BA6820A292000000000000000000" +
+                "00000000000000000000000000000000");
+
+        assignBignum.invoke(bignum, bignum2);
+        multiplyByPowerOfTen.invoke(bignum, 500);
+
+        assertEquals(toHexString.invoke(bignum),
+                "7845F900E475B5086885BAAAE67C8E85185ACFE4633727F82A4B06B5582AC" +
+                "BE933C53357DA0C98C20C5AC900C4D76A97247DF52B79F48F9E35840FB715" +
+                "D392CE303E22622B0CF82D9471B398457DD3196F639CEE8BBD2C146873841" +
+                "F0699E6C41F04FC7A54B48CEB995BEB6F50FE81DE9D87A8D7F849CC523553" +
+                "7B7BBBC1C7CAAFF6E9650BE03B308C6D31012AEF9580F70D3EE2083ADE126" +
+                "8940FA7D6308E239775DFD2F8C97FF7EBD525DAFA6512216F7047A62A93DC" +
+                "38A0165BDC67E250DCC96A0181DE935A70B38704DC71819F02FC5261FF7E1" +
+                "E5F11907678B0A3E519FF4C10A867B0C26CE02BE6960BA8621A87303C101C" +
+                "3F88798BB9F7739655946F8B5744E6B1EAF10B0C5621330F0079209033C69" +
+                "20DE2E2C8D324F0624463735D482BF291926C22A910F5B80FA25170B6B57D" +
+                "8D5928C7BCA3FE87461275F69BD5A1B83181DAAF43E05FC3C72C4E93111B6" +
+                "6205EBF49B28FEDFB7E7526CBDA658A332000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000");
+    }
+
+
+    @Test
+    public void testDivideModuloIntBignum() throws Exception {
+
+        final Object bignum = ctor.newInstance();
+        final Object other = ctor.newInstance();
+        final Object third = ctor.newInstance();
+
+        final Method addBignum = method("addBignum", Bignum);
+        final Method assignBignum = method("assignBignum", Bignum);
+        final Method assignUInt16 = method("assignUInt16", char.class);
+        final Method assignHexString = method("assignHexString", String.class);
+        final Method divideModuloIntBignum = method("divideModuloIntBignum", Bignum);
+        final Method multiplyByUInt32 = method("multiplyByUInt32", int.class);
+        final Method shiftLeft = method("shiftLeft", int.class);
+        final Method subtractBignum = method("subtractBignum", Bignum);
+        final Method toHexString = method("toHexString");
+
+        assignUInt16.invoke(bignum, (char) 10);
+        assignUInt16.invoke(other, (char) 2);
+        assertEquals((char) 5, (char) divideModuloIntBignum.invoke(bignum, other));
+        assertEquals(toHexString.invoke(bignum), "0");
+
+        assignUInt16.invoke(bignum, (char) 10);
+        shiftLeft.invoke(bignum, 500);
+        assignUInt16.invoke(other, (char) 2);
+        shiftLeft.invoke(other, 500);
+        assertEquals((char) 5, (char) divideModuloIntBignum.invoke(bignum, other));
+        assertEquals(toHexString.invoke(bignum), "0");
+
+        assignUInt16.invoke(bignum, (char) 11);
+        assignUInt16.invoke(other, (char) 2);
+        assertEquals((char) 5, (char) divideModuloIntBignum.invoke(bignum, other));
+        assertEquals(toHexString.invoke(bignum), "1");
+
+        assignUInt16.invoke(bignum, (char) 10);
+        shiftLeft.invoke(bignum, 500);
+        assignUInt16.invoke(other, (char) 1);
+        addBignum.invoke(bignum, other);
+        assignUInt16.invoke(other, (char) 2);
+        shiftLeft.invoke(other, 500);
+        assertEquals((char) 5, (char) divideModuloIntBignum.invoke(bignum, other));
+        assertEquals(toHexString.invoke(bignum), "1");
+
+        assignUInt16.invoke(bignum, (char) 10);
+        shiftLeft.invoke(bignum, 500);
+        assignBignum.invoke(other, bignum);
+        multiplyByUInt32.invoke(bignum, 0x1234);
+        assignUInt16.invoke(third, (char) 0xFFF);
+        addBignum.invoke(bignum, third);
+        assertEquals((char) 0x1234, (char) divideModuloIntBignum.invoke(bignum, other));
+        assertEquals(toHexString.invoke(bignum), "FFF");
+
+        assignUInt16.invoke(bignum, (char) 10);
+        assignHexString.invoke(other, "1234567890");
+        assertEquals((char) 0, (char) divideModuloIntBignum.invoke(bignum, other));
+        assertEquals(toHexString.invoke(bignum), "A");
+
+        assignHexString.invoke(bignum, "12345678");
+        assignHexString.invoke(other, "3789012");
+        assertEquals((char) 5, (char) divideModuloIntBignum.invoke(bignum, other));
+        assertEquals(toHexString.invoke(bignum), "D9861E");
+
+        assignHexString.invoke(bignum, "70000001");
+        assignHexString.invoke(other, "1FFFFFFF");
+        assertEquals((char) 3, (char) divideModuloIntBignum.invoke(bignum, other));
+        assertEquals(toHexString.invoke(bignum), "10000004");
+
+        assignHexString.invoke(bignum, "28000000");
+        assignHexString.invoke(other, "12A05F20");
+        assertEquals((char) 2, (char) divideModuloIntBignum.invoke(bignum, other));
+        assertEquals(toHexString.invoke(bignum), "2BF41C0");
+
+        assignUInt16.invoke(bignum, (char) 10);
+        shiftLeft.invoke(bignum, 500);
+        assignBignum.invoke(other, bignum);
+        multiplyByUInt32.invoke(bignum, 0x1234);
+        assignUInt16.invoke(third, (char) 0xFFF);
+        subtractBignum.invoke(other, third);
+        assertEquals((char) 0x1234, (char)  divideModuloIntBignum.invoke(bignum, other));
+        assertEquals(toHexString.invoke(bignum), "1232DCC");
+        assertEquals((char) 0, (char) divideModuloIntBignum.invoke(bignum, other));
+        assertEquals(toHexString.invoke(bignum), "1232DCC");
+    }
+
+
+    @Test
+    public void testCompare() throws Exception {
+
+        final Object bignum1 = ctor.newInstance();
+        final Object bignum2 = ctor.newInstance();
+
+        final Method assignUInt16 = method("assignUInt16", char.class);
+        final Method assignHexString = method("assignHexString", String.class);
+        final Method compare = method("compare", Bignum, Bignum);
+        final Method equal = method("equal", Bignum, Bignum);
+        final Method less = method("less", Bignum, Bignum);
+        final Method lessEqual = method("lessEqual", Bignum, Bignum);
+        final Method shiftLeft = method("shiftLeft", int.class);
+
+        assignUInt16.invoke(bignum1, (char) 1);
+        assignUInt16.invoke(bignum2, (char) 1);
+        assertEquals(0, compare.invoke(null, bignum1, bignum2));
+        assertTrue((boolean) equal.invoke(null, bignum1, bignum2));
+        assertTrue((boolean) lessEqual.invoke(null, bignum1, bignum2));
+        assertTrue(!(boolean) less.invoke(null, bignum1, bignum2));
+
+        assignUInt16.invoke(bignum1, (char) 0);
+        assignUInt16.invoke(bignum2, (char) 1);
+        assertEquals(-1, compare.invoke(null, bignum1, bignum2));
+        assertEquals(+1, compare.invoke(null, bignum2, bignum1));
+        assertTrue(!(boolean) equal.invoke(null, bignum1, bignum2));
+        assertTrue(!(boolean) equal.invoke(null, bignum2, bignum1));
+        assertTrue((boolean) lessEqual.invoke(null, bignum1, bignum2));
+        assertTrue(!(boolean) lessEqual.invoke(null, bignum2, bignum1));
+        assertTrue((boolean) less.invoke(null, bignum1, bignum2));
+        assertTrue(!(boolean) less.invoke(null, bignum2, bignum1));
+
+        assignHexString.invoke(bignum1, "1234567890ABCDEF12345");
+        assignHexString.invoke(bignum2, "1234567890ABCDEF12345");
+        assertEquals(0, compare.invoke(null, bignum1, bignum2));
+
+        assignHexString.invoke(bignum1, "1234567890ABCDEF12345");
+        assignHexString.invoke(bignum2, "1234567890ABCDEF12346");
+        assertEquals(-1, compare.invoke(null, bignum1, bignum2));
+        assertEquals(+1, compare.invoke(null, bignum2, bignum1));
+
+        assignHexString.invoke(bignum1, "1234567890ABCDEF12345");
+        shiftLeft.invoke(bignum1, 500);
+        assignHexString.invoke(bignum2, "1234567890ABCDEF12345");
+        shiftLeft.invoke(bignum2, 500);
+        assertEquals(0, compare.invoke(null, bignum1, bignum2));
+
+        assignHexString.invoke(bignum1, "1234567890ABCDEF12345");
+        shiftLeft.invoke(bignum1, 500);
+        assignHexString.invoke(bignum2, "1234567890ABCDEF12346");
+        shiftLeft.invoke(bignum2, 500);
+        assertEquals(-1, compare.invoke(null, bignum1, bignum2));
+        assertEquals(+1, compare.invoke(null, bignum2, bignum1));
+
+        assignUInt16.invoke(bignum1, (char) 1);
+        shiftLeft.invoke(bignum1, 64);
+        assignHexString.invoke(bignum2, "10000000000000000");
+        assertEquals(0, compare.invoke(null, bignum1, bignum2));
+        assertEquals(0, compare.invoke(null, bignum2, bignum1));
+
+        assignUInt16.invoke(bignum1, (char) 1);
+        shiftLeft.invoke(bignum1, 64);
+        assignHexString.invoke(bignum2, "10000000000000001");
+        assertEquals(-1, compare.invoke(null, bignum1, bignum2));
+        assertEquals(+1, compare.invoke(null, bignum2, bignum1));
+
+        assignUInt16.invoke(bignum1, (char) 1);
+        shiftLeft.invoke(bignum1, 96);
+        assignHexString.invoke(bignum2, "10000000000000001");
+        shiftLeft.invoke(bignum2, 32);
+        assertEquals(-1, compare.invoke(null, bignum1, bignum2));
+        assertEquals(+1, compare.invoke(null, bignum2, bignum1));
+
+        assignHexString.invoke(bignum1, "FFFFFFFFFFFFFFFF");
+        assignUInt16.invoke(bignum2, (char) 1);
+        shiftLeft.invoke(bignum2, 64);
+        assertEquals(-1, compare.invoke(null, bignum1, bignum2));
+        assertEquals(+1, compare.invoke(null, bignum2, bignum1));
+
+        assignHexString.invoke(bignum1, "FFFFFFFFFFFFFFFF");
+        shiftLeft.invoke(bignum1, 32);
+        assignUInt16.invoke(bignum2, (char) 1);
+        shiftLeft.invoke(bignum2, 96);
+        assertEquals(-1, compare.invoke(null, bignum1, bignum2));
+        assertEquals(+1, compare.invoke(null, bignum2, bignum1));
+
+        assignHexString.invoke(bignum1, "FFFFFFFFFFFFFFFF");
+        shiftLeft.invoke(bignum1, 32);
+        assignUInt16.invoke(bignum2, (char) 1);
+        shiftLeft.invoke(bignum2, 95);
+        assertEquals(+1, compare.invoke(null, bignum1, bignum2));
+        assertEquals(-1, compare.invoke(null, bignum2, bignum1));
+
+        assignHexString.invoke(bignum1, "FFFFFFFFFFFFFFFF");
+        shiftLeft.invoke(bignum1, 32);
+        assignUInt16.invoke(bignum2, (char) 1);
+        shiftLeft.invoke(bignum2, 100);
+        assertEquals(-1, compare.invoke(null, bignum1, bignum2));
+        assertEquals(+1, compare.invoke(null, bignum2, bignum1));
+
+        assignHexString.invoke(bignum1, "100000000000000");
+        assignUInt16.invoke(bignum2, (char) 1);
+        shiftLeft.invoke(bignum2, 14*4);
+        assertEquals(0, compare.invoke(null, bignum1, bignum2));
+        assertEquals(0, compare.invoke(null, bignum2, bignum1));
+
+        assignHexString.invoke(bignum1, "100000000000001");
+        assignUInt16.invoke(bignum2, (char) 1);
+        shiftLeft.invoke(bignum2, 14 * 4);
+        assertEquals(+1, compare.invoke(null, bignum1, bignum2));
+        assertEquals(-1, compare.invoke(null, bignum2, bignum1));
+
+        assignHexString.invoke(bignum1, "200000000000000");
+        assignUInt16.invoke(bignum2, (char) 3);
+        shiftLeft.invoke(bignum2, 14*4);
+        assertEquals(-1, compare.invoke(null, bignum1, bignum2));
+        assertEquals(+1, compare.invoke(null, bignum2, bignum1));
+    }
+
+
+    @Test
+    public void testPlusCompare() throws Exception {
+
+        final Object a = ctor.newInstance();
+        final Object b = ctor.newInstance();
+        final Object c = ctor.newInstance();
+
+        final Method assignUInt16 = method("assignUInt16", char.class);
+        final Method assignHexString = method("assignHexString", String.class);
+        final Method plusCompare = method("plusCompare", Bignum, Bignum, Bignum);
+        final Method plusEqual = method("plusEqual", Bignum, Bignum, Bignum);
+        final Method plusLess = method("plusLess", Bignum, Bignum, Bignum);
+        final Method plusLessEqual = method("plusLessEqual", Bignum, Bignum, Bignum);
+        final Method shiftLeft = method("shiftLeft", int.class);
+
+        assignUInt16.invoke(a, (char) 1);
+        assignUInt16.invoke(b, (char) 0);
+        assignUInt16.invoke(c, (char) 1);
+        assertEquals(0, plusCompare.invoke(null, a, b, c));
+        assertTrue((boolean) plusEqual.invoke(null, a, b, c));
+        assertTrue((boolean) plusLessEqual.invoke(null, a, b, c));
+        assertTrue(!(boolean) plusLess.invoke(null, a, b, c));
+
+        assignUInt16.invoke(a, (char) 0);
+        assignUInt16.invoke(b, (char) 0);
+        assignUInt16.invoke(c, (char) 1);
+        assertEquals(-1, plusCompare.invoke(null, a, b, c));
+        assertEquals(+1, plusCompare.invoke(null, c, b, a));
+        assertTrue(!(boolean) plusEqual.invoke(null, a, b, c));
+        assertTrue(!(boolean) plusEqual.invoke(null, c, b, a));
+        assertTrue((boolean) plusLessEqual.invoke(null, a, b, c));
+        assertTrue(!(boolean) plusLessEqual.invoke(null, c, b, a));
+        assertTrue((boolean) plusLess.invoke(null, a, b, c));
+        assertTrue(!(boolean) plusLess.invoke(null, c, b, a));
+
+        assignHexString.invoke(a, "1234567890ABCDEF12345");
+        assignUInt16.invoke(b, (char) 1);
+        assignHexString.invoke(c, "1234567890ABCDEF12345");
+        assertEquals(+1, plusCompare.invoke(null, a, b, c));
+
+        assignHexString.invoke(a, "1234567890ABCDEF12344");
+        assignUInt16.invoke(b, (char) 1);
+        assignHexString.invoke(c, "1234567890ABCDEF12345");
+        assertEquals(0, plusCompare.invoke(null, a, b, c));
+
+        assignHexString.invoke(a, "1234567890");
+        shiftLeft.invoke(a, 11 * 4);
+        assignHexString.invoke(b, "ABCDEF12345");
+        assignHexString.invoke(c, "1234567890ABCDEF12345");
+        assertEquals(0, plusCompare.invoke(null, a, b, c));
+
+        assignHexString.invoke(a, "1234567890");
+        shiftLeft.invoke(a, 11 * 4);
+        assignHexString.invoke(b, "ABCDEF12344");
+        assignHexString.invoke(c, "1234567890ABCDEF12345");
+        assertEquals(-1, plusCompare.invoke(null, a, b, c));
+
+        assignHexString.invoke(a, "1234567890");
+        shiftLeft.invoke(a, 11 * 4);
+        assignHexString.invoke(b, "ABCDEF12346");
+        assignHexString.invoke(c, "1234567890ABCDEF12345");
+        assertEquals(1, plusCompare.invoke(null, a, b, c));
+
+        assignHexString.invoke(a, "1234567891");
+        shiftLeft.invoke(a, 11 * 4);
+        assignHexString.invoke(b, "ABCDEF12345");
+        assignHexString.invoke(c, "1234567890ABCDEF12345");
+        assertEquals(1, plusCompare.invoke(null, a, b, c));
+
+        assignHexString.invoke(a, "1234567889");
+        shiftLeft.invoke(a, 11 * 4);
+        assignHexString.invoke(b, "ABCDEF12345");
+        assignHexString.invoke(c, "1234567890ABCDEF12345");
+        assertEquals(-1, plusCompare.invoke(null, a, b, c));
+
+        assignHexString.invoke(a, "1234567890");
+        shiftLeft.invoke(a, 11 * 4 + 32);
+        assignHexString.invoke(b, "ABCDEF12345");
+        shiftLeft.invoke(b, 32);
+        assignHexString.invoke(c, "1234567890ABCDEF12345");
+        shiftLeft.invoke(c, 32);
+        assertEquals(0, plusCompare.invoke(null, a, b, c));
+
+        assignHexString.invoke(a, "1234567890");
+        shiftLeft.invoke(a, 11 * 4 + 32);
+        assignHexString.invoke(b, "ABCDEF12344");
+        shiftLeft.invoke(b, 32);
+        assignHexString.invoke(c, "1234567890ABCDEF12345");
+        shiftLeft.invoke(c, 32);
+        assertEquals(-1, plusCompare.invoke(null, a, b, c));
+
+        assignHexString.invoke(a, "1234567890");
+        shiftLeft.invoke(a, 11 * 4 + 32);
+        assignHexString.invoke(b, "ABCDEF12346");
+        shiftLeft.invoke(b, 32);
+        assignHexString.invoke(c, "1234567890ABCDEF12345");
+        shiftLeft.invoke(c, 32);
+        assertEquals(1, plusCompare.invoke(null, a, b, c));
+
+        assignHexString.invoke(a, "1234567891");
+        shiftLeft.invoke(a, 11 * 4 + 32);
+        assignHexString.invoke(b, "ABCDEF12345");
+        shiftLeft.invoke(b, 32);
+        assignHexString.invoke(c, "1234567890ABCDEF12345");
+        shiftLeft.invoke(c, 32);
+        assertEquals(1, plusCompare.invoke(null, a, b, c));
+
+        assignHexString.invoke(a, "1234567889");
+        shiftLeft.invoke(a, 11 * 4 + 32);
+        assignHexString.invoke(b, "ABCDEF12345");
+        shiftLeft.invoke(b, 32);
+        assignHexString.invoke(c, "1234567890ABCDEF12345");
+        shiftLeft.invoke(c, 32);
+        assertEquals(-1, plusCompare.invoke(null, a, b, c));
+
+        assignHexString.invoke(a, "1234567890");
+        shiftLeft.invoke(a, 11 * 4 + 32);
+        assignHexString.invoke(b, "ABCDEF12345");
+        shiftLeft.invoke(b, 32);
+        assignHexString.invoke(c, "1234567890ABCDEF1234500000000");
+        assertEquals(0, plusCompare.invoke(null, a, b, c));
+
+        assignHexString.invoke(a, "1234567890");
+        shiftLeft.invoke(a, 11 * 4 + 32);
+        assignHexString.invoke(b, "ABCDEF12344");
+        shiftLeft.invoke(b, 32);
+        assignHexString.invoke(c, "1234567890ABCDEF1234500000000");
+        assertEquals(-1, plusCompare.invoke(null, a, b, c));
+
+        assignHexString.invoke(a, "1234567890");
+        shiftLeft.invoke(a, 11 * 4 + 32);
+        assignHexString.invoke(b, "ABCDEF12346");
+        shiftLeft.invoke(b, 32);
+        assignHexString.invoke(c, "1234567890ABCDEF1234500000000");
+        assertEquals(1, plusCompare.invoke(null, a, b, c));
+
+        assignHexString.invoke(a, "1234567891");
+        shiftLeft.invoke(a, 11 * 4 + 32);
+        assignHexString.invoke(b, "ABCDEF12345");
+        shiftLeft.invoke(b, 32);
+        assignHexString.invoke(c, "1234567890ABCDEF1234500000000");
+        assertEquals(1, plusCompare.invoke(null, a, b, c));
+
+        assignHexString.invoke(a, "1234567889");
+        shiftLeft.invoke(a, 11 * 4 + 32);
+        assignHexString.invoke(b, "ABCDEF12345");
+        shiftLeft.invoke(b, 32);
+        assignHexString.invoke(c, "1234567890ABCDEF1234500000000");
+        assertEquals(-1, plusCompare.invoke(null, a, b, c));
+
+        assignHexString.invoke(a, "1234567890");
+        shiftLeft.invoke(a, 11 * 4 + 32);
+        assignHexString.invoke(b, "ABCDEF12345");
+        assignHexString.invoke(c, "123456789000000000ABCDEF12345");
+        assertEquals(0, plusCompare.invoke(null, a, b, c));
+
+        assignHexString.invoke(a, "1234567890");
+        shiftLeft.invoke(a, 11 * 4 + 32);
+        assignHexString.invoke(b, "ABCDEF12346");
+        assignHexString.invoke(c, "123456789000000000ABCDEF12345");
+        assertEquals(1, plusCompare.invoke(null, a, b, c));
+
+        assignHexString.invoke(a, "1234567890");
+        shiftLeft.invoke(a, 11 * 4 + 32);
+        assignHexString.invoke(b, "ABCDEF12344");
+        assignHexString.invoke(c, "123456789000000000ABCDEF12345");
+        assertEquals(-1, plusCompare.invoke(null, a, b, c));
+
+        assignHexString.invoke(a, "1234567890");
+        shiftLeft.invoke(a, 11 * 4 + 32);
+        assignHexString.invoke(b, "ABCDEF12345");
+        shiftLeft.invoke(b, 16);
+        assignHexString.invoke(c, "12345678900000ABCDEF123450000");
+        assertEquals(0, plusCompare.invoke(null, a, b, c));
+
+        assignHexString.invoke(a, "1234567890");
+        shiftLeft.invoke(a, 11 * 4 + 32);
+        assignHexString.invoke(b, "ABCDEF12344");
+        shiftLeft.invoke(b, 16);
+        assignHexString.invoke(c, "12345678900000ABCDEF123450000");
+        assertEquals(-1, plusCompare.invoke(null, a, b, c));
+
+        assignHexString.invoke(a, "1234567890");
+        shiftLeft.invoke(a, 11 * 4 + 32);
+        assignHexString.invoke(b, "ABCDEF12345");
+        shiftLeft.invoke(b, 16);
+        assignHexString.invoke(c, "12345678900000ABCDEF123450001");
+        assertEquals(-1, plusCompare.invoke(null, a, b, c));
+
+        assignHexString.invoke(a, "1234567890");
+        shiftLeft.invoke(a, 11 * 4 + 32);
+        assignHexString.invoke(b, "ABCDEF12346");
+        shiftLeft.invoke(b, 16);
+        assignHexString.invoke(c, "12345678900000ABCDEF123450000");
+        assertEquals(+1, plusCompare.invoke(null, a, b, c));
+    }
+
+
+    @Test
+    public void testSquare() throws Exception {
+
+        final Object bignum = ctor.newInstance();
+
+        final Method assignUInt16 = method("assignUInt16", char.class);
+        final Method assignHexString = method("assignHexString", String.class);
+        final Method square = method("square");
+        final Method toHexString = method("toHexString");
+
+        assignUInt16.invoke(bignum, (char) 1);
+        square.invoke(bignum);
+        assertEquals(toHexString.invoke(bignum), "1");
+
+        assignUInt16.invoke(bignum, (char) 2);
+        square.invoke(bignum);
+        assertEquals(toHexString.invoke(bignum), "4");
+
+        assignUInt16.invoke(bignum, (char) 10);
+        square.invoke(bignum);
+        assertEquals(toHexString.invoke(bignum), "64");
+
+        assignHexString.invoke(bignum, "FFFFFFF");
+        square.invoke(bignum);
+        assertEquals(toHexString.invoke(bignum), "FFFFFFE0000001");
+
+        assignHexString.invoke(bignum, "FFFFFFFFFFFFFF");
+        square.invoke(bignum);
+        assertEquals(toHexString.invoke(bignum), "FFFFFFFFFFFFFE00000000000001");
+    }
+
+
+    @Test
+    public void testAssignPowerUInt16() throws Exception {
+
+        final Object bignum = ctor.newInstance();
+
+        final Method assignPowerUInt16 = method("assignPowerUInt16", int.class, int.class);
+        final Method toHexString = method("toHexString");
+
+        assignPowerUInt16.invoke(bignum, 1, 0);
+        assertEquals(toHexString.invoke(bignum), "1");
+
+        assignPowerUInt16.invoke(bignum, 1, 1);
+        assertEquals(toHexString.invoke(bignum), "1");
+
+        assignPowerUInt16.invoke(bignum, 1, 2);
+        assertEquals(toHexString.invoke(bignum), "1");
+
+        assignPowerUInt16.invoke(bignum, 2, 0);
+        assertEquals(toHexString.invoke(bignum), "1");
+
+        assignPowerUInt16.invoke(bignum, 2, 1);
+        assertEquals(toHexString.invoke(bignum), "2");
+
+        assignPowerUInt16.invoke(bignum, 2, 2);
+        assertEquals(toHexString.invoke(bignum), "4");
+
+        assignPowerUInt16.invoke(bignum, 16, 1);
+        assertEquals(toHexString.invoke(bignum), "10");
+
+        assignPowerUInt16.invoke(bignum, 16, 2);
+        assertEquals(toHexString.invoke(bignum), "100");
+
+        assignPowerUInt16.invoke(bignum, 16, 5);
+        assertEquals(toHexString.invoke(bignum), "100000");
+
+        assignPowerUInt16.invoke(bignum, 16, 8);
+        assertEquals(toHexString.invoke(bignum), "100000000");
+
+        assignPowerUInt16.invoke(bignum, 16, 16);
+        assertEquals(toHexString.invoke(bignum), "10000000000000000");
+
+        assignPowerUInt16.invoke(bignum, 16, 30);
+        assertEquals(toHexString.invoke(bignum), "1000000000000000000000000000000");
+
+        assignPowerUInt16.invoke(bignum, 10, 0);
+        assertEquals(toHexString.invoke(bignum), "1");
+
+        assignPowerUInt16.invoke(bignum, 10, 1);
+        assertEquals(toHexString.invoke(bignum), "A");
+
+        assignPowerUInt16.invoke(bignum, 10, 2);
+        assertEquals(toHexString.invoke(bignum), "64");
+
+        assignPowerUInt16.invoke(bignum, 10, 5);
+        assertEquals(toHexString.invoke(bignum), "186A0");
+
+        assignPowerUInt16.invoke(bignum, 10, 8);
+        assertEquals(toHexString.invoke(bignum), "5F5E100");
+
+        assignPowerUInt16.invoke(bignum, 10, 16);
+        assertEquals(toHexString.invoke(bignum), "2386F26FC10000");
+
+        assignPowerUInt16.invoke(bignum, 10, 30);
+        assertEquals(toHexString.invoke(bignum), "C9F2C9CD04674EDEA40000000");
+
+        assignPowerUInt16.invoke(bignum, 10, 31);
+        assertEquals(toHexString.invoke(bignum), "7E37BE2022C0914B2680000000");
+
+        assignPowerUInt16.invoke(bignum, 2, 0);
+        assertEquals(toHexString.invoke(bignum), "1");
+
+        assignPowerUInt16.invoke(bignum, 2, 100);
+        assertEquals(toHexString.invoke(bignum), "10000000000000000000000000");
+
+        assignPowerUInt16.invoke(bignum, 17, 0);
+        assertEquals(toHexString.invoke(bignum), "1");
+
+        assignPowerUInt16.invoke(bignum, 17, 99);
+        assertEquals(toHexString.invoke(bignum),
+                "1942BB9853FAD924A3D4DD92B89B940E0207BEF05DB9C26BC1B757" +
+                "80BE0C5A2C2990E02A681224F34ED68558CE4C6E33760931");
+
+        assignPowerUInt16.invoke(bignum, 0xFFFF, 99);
+        assertEquals(toHexString.invoke(bignum),
+                "FF9D12F09B886C54E77E7439C7D2DED2D34F669654C0C2B6B8C288250" +
+                "5A2211D0E3DC9A61831349EAE674B11D56E3049D7BD79DAAD6C9FA2BA" +
+                "528E3A794299F2EE9146A324DAFE3E88967A0358233B543E233E575B9" +
+                "DD4E3AA7942146426C328FF55BFD5C45E0901B1629260AF9AE2F310C5" +
+                "50959FAF305C30116D537D80CF6EBDBC15C5694062AF1AC3D956D0A41" +
+                "B7E1B79FF11E21D83387A1CE1F5882B31E4B5D8DE415BDBE6854466DF" +
+                "343362267A7E8833119D31D02E18DB5B0E8F6A64B0ED0D0062FFFF");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/src/jdk/nashorn/internal/runtime/doubleconv/test/DiyFpTest.java	Wed Nov 11 15:22:14 2015 +0100
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// This file is available under and governed by the GNU General Public
+// License version 2 only, as published by the Free Software Foundation.
+// However, the following notice accompanied the original version of this
+// file:
+//
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+
+package jdk.nashorn.internal.runtime.doubleconv.test;
+
+import org.testng.annotations.Test;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * DiyFp class tests
+ *
+ * @test
+ * @run testng jdk.nashorn.internal.runtime.doubleconv.test.DiyFpTest
+ */
+@SuppressWarnings("javadoc")
+public class DiyFpTest {
+
+    static final Class<?> DiyFp;
+    static final Constructor<?> ctor;
+
+    static {
+        try {
+            DiyFp = Class.forName("jdk.nashorn.internal.runtime.doubleconv.DiyFp");
+            ctor = DiyFp.getDeclaredConstructor(long.class, int.class);
+            ctor.setAccessible(true);
+        } catch (final Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static Method method(final String name, final Class<?>... params) throws NoSuchMethodException {
+        final Method m = DiyFp.getDeclaredMethod(name, params);
+        m.setAccessible(true);
+        return m;
+    }
+
+    @Test
+    public void testSubtract() throws Exception {
+        final Object diyFp1 = ctor.newInstance(3, 0);
+        final Object diyFp2 = ctor.newInstance(1, 0);
+        final Object diff = method("minus", DiyFp, DiyFp).invoke(null, diyFp1, diyFp2);;
+        assertTrue(2l == (long) method("f").invoke(diff));
+        assertTrue(0 == (int) method("e").invoke(diff));
+        method("subtract", DiyFp).invoke(diyFp1, diyFp2);
+        assertTrue(2l == (long) method("f").invoke(diyFp1));
+        assertTrue(0 == (int) method("e").invoke(diyFp2));
+    }
+
+    @Test
+    public void testMultiply() throws Exception {
+        Object diyFp1, diyFp2, product;
+
+        diyFp1 = ctor.newInstance(3, 0);
+        diyFp2 = ctor.newInstance(2, 0);
+        product = method("times", DiyFp, DiyFp).invoke(null, diyFp1, diyFp2);
+        assertEquals(0l, (long) method("f").invoke(product));
+        assertEquals(64, (int) method("e").invoke(product));
+        method("multiply", DiyFp).invoke(diyFp1, diyFp2);
+        assertEquals(0l, (long) method("f").invoke(diyFp1));
+        assertEquals(64, (int) method("e").invoke(diyFp1));
+
+        diyFp1 = ctor.newInstance(0x8000000000000000L, 11);
+        diyFp2 = ctor.newInstance(2, 13);
+        product = method("times", DiyFp, DiyFp).invoke(null, diyFp1, diyFp2);
+        assertEquals(1l, (long) method("f").invoke(product));
+        assertEquals(11 + 13 + 64, (int) method("e").invoke(product));
+
+        // Test rounding.
+        diyFp1 = ctor.newInstance(0x8000000000000001L, 11);
+        diyFp2 = ctor.newInstance(1, 13);
+        product = method("times", DiyFp, DiyFp).invoke(null, diyFp1, diyFp2);
+        assertEquals(1l, (long) method("f").invoke(product));
+        assertEquals(11 + 13 + 64, (int) method("e").invoke(product));
+
+        diyFp1 = ctor.newInstance(0x7fffffffffffffffL, 11);
+        diyFp2 = ctor.newInstance(1, 13);
+        product = method("times", DiyFp, DiyFp).invoke(null, diyFp1, diyFp2);
+        assertEquals(0l, (long) method("f").invoke(product));
+        assertEquals(11 + 13 + 64, (int) method("e").invoke(product));
+
+        // Big numbers.
+        diyFp1 = ctor.newInstance(0xFFFFFFFFFFFFFFFFL, 11);
+        diyFp2 = ctor.newInstance(0xFFFFFFFFFFFFFFFFL, 13);
+        // 128bit result: 0xfffffffffffffffe0000000000000001
+        product = method("times", DiyFp, DiyFp).invoke(null, diyFp1, diyFp2);
+        assertEquals(0xFFFFFFFFFFFFFFFel, (long) method("f").invoke(product));
+        assertEquals(11 + 13 + 64, (int) method("e").invoke(product));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/src/jdk/nashorn/internal/runtime/doubleconv/test/FastDtoaTest.java	Wed Nov 11 15:22:14 2015 +0100
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// This file is available under and governed by the GNU General Public
+// License version 2 only, as published by the Free Software Foundation.
+// However, the following notice accompanied the original version of this
+// file:
+//
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+
+package jdk.nashorn.internal.runtime.doubleconv.test;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import jdk.nashorn.internal.runtime.doubleconv.DoubleConversion;
+import jdk.nashorn.internal.runtime.doubleconv.DtoaBuffer;
+
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * FastDtoa tests
+ *
+ * @test
+ * @run testng jdk.nashorn.internal.runtime.doubleconv.test.FastDtoaTest
+ */
+@SuppressWarnings("javadoc")
+public class FastDtoaTest {
+
+    final static private int kBufferSize = 100;
+
+    // Removes trailing '0' digits.
+    // Can return the empty string if all digits are 0.
+    private static String trimRepresentation(final String representation) {
+        final int len = representation.length();
+        int i;
+        for (i = len - 1; i >= 0; --i) {
+            if (representation.charAt(i) != '0') break;
+        }
+        return representation.substring(0, i + 1);
+    }
+
+    @Test
+    public void testFastShortestVarious() {
+        final DtoaBuffer buffer = new DtoaBuffer(kBufferSize);
+        boolean status;
+
+        final double min_double = 5e-324;
+        status = DoubleConversion.fastDtoaShortest(min_double, buffer);
+        assertTrue(status);
+        assertEquals("5", buffer.getRawDigits());
+        assertEquals(-323, buffer.getDecimalPoint());
+        buffer.reset();
+
+        final double max_double = 1.7976931348623157e308;
+        status = DoubleConversion.fastDtoaShortest(max_double, buffer);
+        assertTrue(status);
+        assertEquals("17976931348623157", buffer.getRawDigits());
+        assertEquals(309, buffer.getDecimalPoint());
+        buffer.reset();
+
+
+        status = DoubleConversion.fastDtoaShortest(4294967272.0, buffer);
+        assertTrue(status);
+        assertEquals("4294967272", buffer.getRawDigits());
+        assertEquals(10, buffer.getDecimalPoint());
+        buffer.reset();
+
+
+        status = DoubleConversion.fastDtoaShortest(4.1855804968213567e298, buffer);
+        assertTrue(status);
+        assertEquals("4185580496821357", buffer.getRawDigits());
+        assertEquals(299, buffer.getDecimalPoint());
+        buffer.reset();
+
+        status = DoubleConversion.fastDtoaShortest(5.5626846462680035e-309, buffer);
+        assertTrue(status);
+        assertEquals("5562684646268003", buffer.getRawDigits());
+        assertEquals(-308, buffer.getDecimalPoint());
+        buffer.reset();
+
+        status = DoubleConversion.fastDtoaShortest(2147483648.0, buffer);
+        assertTrue(status);
+        assertEquals("2147483648", buffer.getRawDigits());
+        assertEquals(10, buffer.getDecimalPoint());
+        buffer.reset();
+
+        status = DoubleConversion.fastDtoaShortest(3.5844466002796428e+298, buffer);
+        if (status) {  // Not all FastDtoa variants manage to compute this number.
+            assertEquals("35844466002796428", buffer.getRawDigits());
+            assertEquals(299, buffer.getDecimalPoint());
+        }
+        buffer.reset();
+
+        final long smallest_normal64 = 0x0010000000000000L;
+        double v = Double.longBitsToDouble(smallest_normal64);
+        status = DoubleConversion.fastDtoaShortest(v, buffer);
+        if (status) {
+            assertEquals("22250738585072014", buffer.getRawDigits());
+            assertEquals(-307, buffer.getDecimalPoint());
+        }
+        buffer.reset();
+
+        final long largest_denormal64 = 0x000FFFFFFFFFFFFFL;
+        v = Double.longBitsToDouble(largest_denormal64);
+        status = DoubleConversion.fastDtoaShortest(v, buffer);
+        if (status) {
+            assertEquals("2225073858507201", buffer.getRawDigits());
+            assertEquals(-307, buffer.getDecimalPoint());
+        }
+        buffer.reset();
+    }
+
+    @Test
+    public void testFastPrecisionVarious() {
+        final DtoaBuffer buffer = new DtoaBuffer(kBufferSize);
+        boolean status;
+
+        status = DoubleConversion.fastDtoaCounted(1.0, 3, buffer);
+        assertTrue(status);
+        assertTrue(3 >= buffer.getLength());
+        assertEquals("1", trimRepresentation(buffer.getRawDigits()));
+        assertEquals(1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        status = DoubleConversion.fastDtoaCounted(1.5, 10, buffer);
+        if (status) {
+            assertTrue(10 >= buffer.getLength());
+            assertEquals("15", trimRepresentation(buffer.getRawDigits()));
+            assertEquals(1, buffer.getDecimalPoint());
+        }
+        buffer.reset();
+
+        final double min_double = 5e-324;
+        status = DoubleConversion.fastDtoaCounted(min_double, 5, buffer);
+        assertTrue(status);
+        assertEquals("49407", buffer.getRawDigits());
+        assertEquals(-323, buffer.getDecimalPoint());
+        buffer.reset();
+
+        final double max_double = 1.7976931348623157e308;
+        status = DoubleConversion.fastDtoaCounted(max_double, 7, buffer);
+        assertTrue(status);
+        assertEquals("1797693", buffer.getRawDigits());
+        assertEquals(309, buffer.getDecimalPoint());
+        buffer.reset();
+
+        status = DoubleConversion.fastDtoaCounted(4294967272.0, 14, buffer);
+        if (status) {
+            assertTrue(14 >= buffer.getLength());
+            assertEquals("4294967272", trimRepresentation(buffer.getRawDigits()));
+            assertEquals(10, buffer.getDecimalPoint());
+        }
+        buffer.reset();
+
+        status = DoubleConversion.fastDtoaCounted(4.1855804968213567e298, 17, buffer);
+        assertTrue(status);
+        assertEquals("41855804968213567", buffer.getRawDigits());
+        assertEquals(299, buffer.getDecimalPoint());
+        buffer.reset();
+
+        status = DoubleConversion.fastDtoaCounted(5.5626846462680035e-309, 1, buffer);
+        assertTrue(status);
+        assertEquals("6", buffer.getRawDigits());
+        assertEquals(-308, buffer.getDecimalPoint());
+        buffer.reset();
+
+        status = DoubleConversion.fastDtoaCounted(2147483648.0, 5, buffer);
+        assertTrue(status);
+        assertEquals("21475", buffer.getRawDigits());
+        assertEquals(10, buffer.getDecimalPoint());
+        buffer.reset();
+
+        status = DoubleConversion.fastDtoaCounted(3.5844466002796428e+298, 10, buffer);
+        assertTrue(status);
+        assertTrue(10 >= buffer.getLength());
+        assertEquals("35844466", trimRepresentation(buffer.getRawDigits()));
+        assertEquals(299, buffer.getDecimalPoint());
+        buffer.reset();
+
+        final long smallest_normal64 = 0x0010000000000000L;
+        double v = Double.longBitsToDouble(smallest_normal64);
+        status = DoubleConversion.fastDtoaCounted(v, 17, buffer);
+        assertTrue(status);
+        assertEquals("22250738585072014", buffer.getRawDigits());
+        assertEquals(-307, buffer.getDecimalPoint());
+        buffer.reset();
+
+        final long largest_denormal64 = 0x000FFFFFFFFFFFFFL;
+        v = Double.longBitsToDouble(largest_denormal64);
+        status = DoubleConversion.fastDtoaCounted(v, 17, buffer);
+        assertTrue(status);
+        assertTrue(20 >= buffer.getLength());
+        assertEquals("22250738585072009", trimRepresentation(buffer.getRawDigits()));
+        assertEquals(-307, buffer.getDecimalPoint());
+        buffer.reset();
+
+        v = 3.3161339052167390562200598e-237;
+        status = DoubleConversion.fastDtoaCounted(v, 18, buffer);
+        assertTrue(status);
+        assertEquals("331613390521673906", buffer.getRawDigits());
+        assertEquals(-236, buffer.getDecimalPoint());
+        buffer.reset();
+
+        v = 7.9885183916008099497815232e+191;
+        status = DoubleConversion.fastDtoaCounted(v, 4, buffer);
+        assertTrue(status);
+        assertEquals("7989", buffer.getRawDigits());
+        assertEquals(192, buffer.getDecimalPoint());
+        buffer.reset();
+    }
+
+
+    @Test
+    public void testFastShortest() {
+        final AtomicInteger total = new AtomicInteger();
+        final AtomicInteger succeeded = new AtomicInteger();
+        final AtomicBoolean neededMaxLength = new AtomicBoolean();
+
+        new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("resources/gay-shortest.txt")))
+                .lines()
+                .forEach(line -> {
+                    if (line.isEmpty() || line.startsWith("//")) {
+                        return; // comment or empty line
+                    }
+                    final String[] tokens = line.split(",\\s+");
+                    assertEquals(tokens.length, 3, "*" + line + "*");
+                    final double v = Double.parseDouble(tokens[0]);
+                    final String str = tokens[1].replace('"', ' ').trim();;
+                    final int point = Integer.parseInt(tokens[2]);
+                    final DtoaBuffer buffer = new DtoaBuffer(kBufferSize);
+                    total.getAndIncrement();
+
+                    if (DoubleConversion.fastDtoaShortest(v, buffer)) {
+                        assertEquals(str, buffer.getRawDigits());
+                        assertEquals(point, buffer.getDecimalPoint());
+                        succeeded.getAndIncrement();
+                        if (buffer.getLength() == DtoaBuffer.kFastDtoaMaximalLength) {
+                            neededMaxLength.set(true);
+                        }
+                    }
+                });
+
+        assertTrue(succeeded.get() * 1.0 / total.get() > 0.99);
+        assertTrue(neededMaxLength.get());
+        // Additional constraints: Make sure these numbers are exactly the same as in C++ version
+        assertEquals(succeeded.get(), 99440);
+        assertEquals(total.get(), 100000);
+    }
+
+    @Test
+    public void testFastPrecision() {
+        final AtomicInteger total = new AtomicInteger();
+        final AtomicInteger succeeded = new AtomicInteger();
+        // Count separately for entries with less than 15 requested digits.
+        final AtomicInteger  succeeded_15  = new AtomicInteger();
+        final AtomicInteger  total_15 = new AtomicInteger();
+
+        new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("resources/gay-precision.txt")))
+                .lines()
+                .forEach(line -> {
+                    if (line.isEmpty() || line.startsWith("//")) {
+                        return; // comment or empty line
+                    }
+                    final String[] tokens = line.split(",\\s+");
+                    assertEquals(tokens.length, 4);
+                    final double v = Double.parseDouble(tokens[0]);
+                    final int digits = Integer.parseInt(tokens[1]);
+                    final String str = tokens[2].replace('"', ' ').trim();
+                    final int point = Integer.parseInt(tokens[3]);
+                    final DtoaBuffer buffer = new DtoaBuffer(kBufferSize);
+                    total.getAndIncrement();
+                    if (digits <= 15) {
+                        total_15.getAndIncrement();
+                    }
+
+                    if (DoubleConversion.fastDtoaCounted(v, digits, buffer)) {
+                        assertEquals(str, trimRepresentation(buffer.getRawDigits()));
+                        assertEquals(point, buffer.getDecimalPoint());
+                        succeeded.getAndIncrement();
+                        if (digits <= 15) {
+                            succeeded_15.getAndIncrement();
+                        }
+                    }
+                });
+
+        // The precomputed numbers contain many entries with many requested
+        // digits. These have a high failure rate and we therefore expect a lower
+        // success rate than for the shortest representation.
+        assertTrue(succeeded.get() * 1.0 / total.get() > 0.85);
+        // However with less than 15 digits almost the algorithm should almost always
+        // succeed.
+        assertTrue(succeeded_15.get() * 1.0 / total_15.get() > 0.9999);
+        // Additional constraints: Make sure these numbers are exactly the same as in C++ version
+        assertEquals(succeeded.get(), 86866);
+        assertEquals(total.get(), 100000);
+        assertEquals(succeeded_15.get(), 71328);
+        assertEquals(total_15.get(), 71330);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/src/jdk/nashorn/internal/runtime/doubleconv/test/FixedDtoaTest.java	Wed Nov 11 15:22:14 2015 +0100
@@ -0,0 +1,665 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// This file is available under and governed by the GNU General Public
+// License version 2 only, as published by the Free Software Foundation.
+// However, the following notice accompanied the original version of this
+// file:
+//
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package jdk.nashorn.internal.runtime.doubleconv.test;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.util.concurrent.atomic.AtomicInteger;
+import jdk.nashorn.internal.runtime.doubleconv.DoubleConversion;
+import jdk.nashorn.internal.runtime.doubleconv.DtoaBuffer;
+
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * FixedDtoa tests
+ *
+ * @test
+ * @run testng jdk.nashorn.internal.runtime.doubleconv.test.FixedDtoaTest
+ */
+@SuppressWarnings("javadoc")
+public class FixedDtoaTest {
+
+    static final int kBufferSize = 500;
+
+    @Test
+    public void testFastShortestVarious() {
+        final DtoaBuffer buffer = new DtoaBuffer(kBufferSize);
+
+        assertTrue(DoubleConversion.fixedDtoa(1.0, 1, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(1.0, 15, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(1.0, 0, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0xFFFFFFFFL, 5, buffer));
+        assertEquals("4294967295", buffer.getRawDigits());
+        assertEquals(10, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(4294967296.0, 5, buffer));
+        assertEquals("4294967296", buffer.getRawDigits());
+        assertEquals(10, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(1e21, 5, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(22, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(999999999999999868928.00, 2, buffer));
+        assertEquals("999999999999999868928", buffer.getRawDigits());
+        assertEquals(21, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(6.9999999999999989514240000e+21, 5, buffer));
+        assertEquals("6999999999999998951424", buffer.getRawDigits());
+        assertEquals(22, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(1.5, 5, buffer));
+        assertEquals("15", buffer.getRawDigits());
+        assertEquals(1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(1.55, 5, buffer));
+        assertEquals("155", buffer.getRawDigits());
+        assertEquals(1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(1.55, 1, buffer));
+        assertEquals("16", buffer.getRawDigits());
+        assertEquals(1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(1.00000001, 15, buffer));
+        assertEquals("100000001", buffer.getRawDigits());
+        assertEquals(1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.1, 10, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(0, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.01, 10, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.001, 10, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-2, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.0001, 10, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-3, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.00001, 10, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-4, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.000001, 10, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-5, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.0000001, 10, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-6, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.00000001, 10, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-7, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.000000001, 10, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-8, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.0000000001, 15, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-9, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.00000000001, 15, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-10, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.000000000001, 15, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-11, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.0000000000001, 15, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-12, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.00000000000001, 15, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-13, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.000000000000001, 20, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-14, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.0000000000000001, 20, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-15, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.00000000000000001, 20, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-16, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.000000000000000001, 20, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-17, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.0000000000000000001, 20, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-18, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.00000000000000000001, 20, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-19, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.10000000004, 10, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(0, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.01000000004, 10, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.00100000004, 10, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-2, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.00010000004, 10, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-3, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.00001000004, 10, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-4, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.00000100004, 10, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-5, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.00000010004, 10, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-6, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.00000001004, 10, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-7, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.00000000104, 10, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-8, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.0000000001000004, 15, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-9, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.0000000000100004, 15, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-10, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.0000000000010004, 15, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-11, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.0000000000001004, 15, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-12, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.0000000000000104, 15, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-13, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.000000000000001000004, 20, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-14, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.000000000000000100004, 20, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-15, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.000000000000000010004, 20, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-16, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.000000000000000001004, 20, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-17, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.000000000000000000104, 20, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-18, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.000000000000000000014, 20, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-19, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.10000000006, 10, buffer));
+        assertEquals("1000000001", buffer.getRawDigits());
+        assertEquals(0, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.01000000006, 10, buffer));
+        assertEquals("100000001", buffer.getRawDigits());
+        assertEquals(-1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.00100000006, 10, buffer));
+        assertEquals("10000001", buffer.getRawDigits());
+        assertEquals(-2, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.00010000006, 10, buffer));
+        assertEquals("1000001", buffer.getRawDigits());
+        assertEquals(-3, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.00001000006, 10, buffer));
+        assertEquals("100001", buffer.getRawDigits());
+        assertEquals(-4, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.00000100006, 10, buffer));
+        assertEquals("10001", buffer.getRawDigits());
+        assertEquals(-5, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.00000010006, 10, buffer));
+        assertEquals("1001", buffer.getRawDigits());
+        assertEquals(-6, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.00000001006, 10, buffer));
+        assertEquals("101", buffer.getRawDigits());
+        assertEquals(-7, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.00000000106, 10, buffer));
+        assertEquals("11", buffer.getRawDigits());
+        assertEquals(-8, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.0000000001000006, 15, buffer));
+        assertEquals("100001", buffer.getRawDigits());
+        assertEquals(-9, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.0000000000100006, 15, buffer));
+        assertEquals("10001", buffer.getRawDigits());
+        assertEquals(-10, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.0000000000010006, 15, buffer));
+        assertEquals("1001", buffer.getRawDigits());
+        assertEquals(-11, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.0000000000001006, 15, buffer));
+        assertEquals("101", buffer.getRawDigits());
+        assertEquals(-12, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.0000000000000106, 15, buffer));
+        assertEquals("11", buffer.getRawDigits());
+        assertEquals(-13, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.000000000000001000006, 20, buffer));
+        assertEquals("100001", buffer.getRawDigits());
+        assertEquals(-14, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.000000000000000100006, 20, buffer));
+        assertEquals("10001", buffer.getRawDigits());
+        assertEquals(-15, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.000000000000000010006, 20, buffer));
+        assertEquals("1001", buffer.getRawDigits());
+        assertEquals(-16, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.000000000000000001006, 20, buffer));
+        assertEquals("101", buffer.getRawDigits());
+        assertEquals(-17, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.000000000000000000106, 20, buffer));
+        assertEquals("11", buffer.getRawDigits());
+        assertEquals(-18, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.000000000000000000016, 20, buffer));
+        assertEquals("2", buffer.getRawDigits());
+        assertEquals(-19, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.6, 0, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.96, 1, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.996, 2, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.9996, 3, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.99996, 4, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.999996, 5, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.9999996, 6, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.99999996, 7, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.999999996, 8, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.9999999996, 9, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.99999999996, 10, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.999999999996, 11, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.9999999999996, 12, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.99999999999996, 13, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.999999999999996, 14, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.9999999999999996, 15, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.00999999999999996, 16, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.000999999999999996, 17, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-2, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.0000999999999999996, 18, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-3, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.00000999999999999996, 19, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-4, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.000000999999999999996, 20, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-5, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(323423.234234, 10, buffer));
+        assertEquals("323423234234", buffer.getRawDigits());
+        assertEquals(6, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(12345678.901234, 4, buffer));
+        assertEquals("123456789012", buffer.getRawDigits());
+        assertEquals(8, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(98765.432109, 5, buffer));
+        assertEquals("9876543211", buffer.getRawDigits());
+        assertEquals(5, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(42, 20, buffer));
+        assertEquals("42", buffer.getRawDigits());
+        assertEquals(2, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(0.5, 0, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(1, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(1e-23, 10, buffer));
+        assertEquals("", buffer.getRawDigits());
+        assertEquals(-10, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(1e-123, 2, buffer));
+        assertEquals("", buffer.getRawDigits());
+        assertEquals(-2, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(1e-123, 0, buffer));
+        assertEquals("", buffer.getRawDigits());
+        assertEquals(0, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(1e-23, 20, buffer));
+        assertEquals("", buffer.getRawDigits());
+        assertEquals(-20, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(1e-21, 20, buffer));
+        assertEquals("", buffer.getRawDigits());
+        assertEquals(-20, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(1e-22, 20, buffer));
+        assertEquals("", buffer.getRawDigits());
+        assertEquals(-20, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(6e-21, 20, buffer));
+        assertEquals("1", buffer.getRawDigits());
+        assertEquals(-19, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(9.1193616301674545152000000e+19, 0, buffer));
+        assertEquals("91193616301674545152", buffer.getRawDigits());
+        assertEquals(20, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(4.8184662102767651659096515e-04, 19, buffer));
+        assertEquals("4818466210276765", buffer.getRawDigits());
+        assertEquals(-3, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(1.9023164229540652612705182e-23, 8, buffer));
+        assertEquals("", buffer.getRawDigits());
+        assertEquals(-8, buffer.getDecimalPoint());
+        buffer.reset();
+
+        assertTrue(DoubleConversion.fixedDtoa(1000000000000000128.0, 0, buffer));
+        assertEquals("1000000000000000128", buffer.getRawDigits());
+        assertEquals(19, buffer.getDecimalPoint());
+        buffer.reset();
+    }
+
+
+
+    @Test
+    public void testFastFixed() {
+        final AtomicInteger total = new AtomicInteger();
+        final AtomicInteger succeeded = new AtomicInteger();
+
+        new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("resources/gay-fixed.txt")))
+                .lines()
+                .forEach(line -> {
+                    if (line.isEmpty() || line.startsWith("//")) {
+                        return; // comment or empty line
+                    }
+                    final String[] tokens = line.split(",\\s+");
+                    assertEquals(tokens.length, 4);
+                    final double v = Double.parseDouble(tokens[0]);
+                    final int digits = Integer.parseInt(tokens[1]);
+                    final String str = tokens[2].replace('"', ' ').trim();;
+                    final int point = Integer.parseInt(tokens[3]);
+                    final DtoaBuffer buffer = new DtoaBuffer(kBufferSize);
+                    total.getAndIncrement();
+
+                    if (DoubleConversion.fixedDtoa(v, digits, buffer)) {
+                        assertEquals(str, buffer.getRawDigits());
+                        assertEquals(point, buffer.getDecimalPoint());
+                        succeeded.getAndIncrement();
+                    }
+                });
+
+        // should work for all numbers
+        assertEquals(succeeded.get(), total.get());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/src/jdk/nashorn/internal/runtime/doubleconv/test/IeeeDoubleTest.java	Wed Nov 11 15:22:14 2015 +0100
@@ -0,0 +1,332 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// This file is available under and governed by the GNU General Public
+// License version 2 only, as published by the Free Software Foundation.
+// However, the following notice accompanied the original version of this
+// file:
+//
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+
+package jdk.nashorn.internal.runtime.doubleconv.test;
+
+import org.testng.annotations.Test;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * Ieee class tests
+ *
+ * @test
+ * @run testng jdk.nashorn.internal.runtime.doubleconv.test.IeeeTest
+ */
+@SuppressWarnings({"unchecked", "javadoc"})
+public class IeeeDoubleTest {
+
+    static final Method asDiyFp;
+    static final Method asNormalizedDiyFp;
+    static final Method doubleToLong;
+    static final Method longToDouble;
+    static final Method isDenormal;
+    static final Method isSpecial;
+    static final Method isInfinite;
+    static final Method isNaN;
+    static final Method value;
+    static final Method sign;
+    static final Method nextDouble;
+    static final Method previousDouble;
+    static final Method normalizedBoundaries;
+    static final Method Infinity;
+    static final Method NaN;
+    static final Method f;
+    static final Method e;
+    static final Constructor<?> DiyFpCtor;
+
+    static {
+        try {
+            final Class<?> IeeeDouble = Class.forName("jdk.nashorn.internal.runtime.doubleconv.IeeeDouble");
+            final Class DiyFp = Class.forName("jdk.nashorn.internal.runtime.doubleconv.DiyFp");
+            asDiyFp = method(IeeeDouble, "asDiyFp", long.class);
+            asNormalizedDiyFp = method(IeeeDouble, "asNormalizedDiyFp", long.class);
+            doubleToLong = method(IeeeDouble, "doubleToLong", double.class);
+            longToDouble = method(IeeeDouble, "longToDouble", long.class);
+            isDenormal = method(IeeeDouble, "isDenormal", long.class);
+            isSpecial = method(IeeeDouble, "isSpecial", long.class);
+            isInfinite = method(IeeeDouble, "isInfinite", long.class);
+            isNaN = method(IeeeDouble, "isNaN", long.class);
+            value = method(IeeeDouble, "value", long.class);
+            sign = method(IeeeDouble, "sign", long.class);
+            nextDouble = method(IeeeDouble, "nextDouble", long.class);
+            previousDouble = method(IeeeDouble, "previousDouble", long.class);
+            Infinity = method(IeeeDouble, "Infinity");
+            NaN = method(IeeeDouble, "NaN");
+            normalizedBoundaries = method(IeeeDouble, "normalizedBoundaries", long.class, DiyFp, DiyFp);
+            DiyFpCtor = DiyFp.getDeclaredConstructor();
+            DiyFpCtor.setAccessible(true);
+            f = method(DiyFp, "f");
+            e = method(DiyFp, "e");
+        } catch (final Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static Method method(final Class<?> clazz, final String name, final Class<?>... params) throws NoSuchMethodException {
+        final Method m = clazz.getDeclaredMethod(name, params);
+        m.setAccessible(true);
+        return m;
+    }
+
+    @Test
+    public void testUint64Conversions() throws Exception {
+        // Start by checking the byte-order.
+        final long ordered = 0x0123456789ABCDEFL;
+        assertEquals(3512700564088504e-318, value.invoke(null, ordered));
+
+        final long min_double64 = 0x0000000000000001L;
+        assertEquals(5e-324, value.invoke(null, min_double64));
+
+        final long max_double64 = 0x7fefffffffffffffL;
+        assertEquals(1.7976931348623157e308, value.invoke(null, max_double64));
+    }
+
+
+    @Test
+    public void testDoubleAsDiyFp() throws Exception {
+        final long ordered = 0x0123456789ABCDEFL;
+        Object diy_fp = asDiyFp.invoke(null, ordered);
+        assertEquals(0x12 - 0x3FF - 52, e.invoke(diy_fp));
+        // The 52 mantissa bits, plus the implicit 1 in bit 52 as a UINT64.
+        assertTrue(0x0013456789ABCDEFL == (long) f.invoke(diy_fp));
+
+        final long min_double64 = 0x0000000000000001L;
+        diy_fp = asDiyFp.invoke(null, min_double64);
+        assertEquals(-0x3FF - 52 + 1, e.invoke(diy_fp));
+        // This is a denormal; so no hidden bit.
+        assertTrue(1L == (long) f.invoke(diy_fp));
+
+        final long max_double64 = 0x7fefffffffffffffL;
+        diy_fp = asDiyFp.invoke(null, max_double64);
+        assertEquals(0x7FE - 0x3FF - 52, e.invoke(diy_fp));
+        assertTrue(0x001fffffffffffffL == (long) f.invoke(diy_fp));
+    }
+
+
+    @Test
+    public void testAsNormalizedDiyFp() throws Exception {
+        final long ordered = 0x0123456789ABCDEFL;
+        Object diy_fp = asNormalizedDiyFp.invoke(null, ordered);
+        assertEquals(0x12 - 0x3FF - 52 - 11, (int) e.invoke(diy_fp));
+        assertTrue((0x0013456789ABCDEFL << 11) == (long) f.invoke(diy_fp));
+
+        final long min_double64 = 0x0000000000000001L;
+        diy_fp = asNormalizedDiyFp.invoke(null, min_double64);
+        assertEquals(-0x3FF - 52 + 1 - 63, e.invoke(diy_fp));
+        // This is a denormal; so no hidden bit.
+        assertTrue(0x8000000000000000L == (long) f.invoke(diy_fp));
+
+        final long max_double64 = 0x7fefffffffffffffL;
+        diy_fp = asNormalizedDiyFp.invoke(null, max_double64);
+        assertEquals(0x7FE - 0x3FF - 52 - 11, e.invoke(diy_fp));
+        assertTrue((0x001fffffffffffffL << 11) == (long) f.invoke(diy_fp));
+    }
+
+
+    @Test
+    public void testIsDenormal() throws Exception {
+        final long min_double64 = 0x0000000000000001L;
+        assertTrue((boolean) isDenormal.invoke(null, min_double64));
+        long bits = 0x000FFFFFFFFFFFFFL;
+        assertTrue((boolean) isDenormal.invoke(null, bits));
+        bits = 0x0010000000000000L;
+        assertTrue(!(boolean) isDenormal.invoke(null, bits));
+    }
+
+    @Test
+    public void testIsSpecial() throws Exception {
+        assertTrue((boolean) isSpecial.invoke(null, doubleToLong.invoke(null, Infinity.invoke(null))));
+        assertTrue((boolean) isSpecial.invoke(null, doubleToLong.invoke(null, -(double) Infinity.invoke(null))));
+        assertTrue((boolean) isSpecial.invoke(null, doubleToLong.invoke(null, NaN.invoke(null))));
+        final long bits = 0xFFF1234500000000L;
+        assertTrue((boolean) isSpecial.invoke(null, bits));
+        // Denormals are not special:
+        assertTrue(!(boolean) isSpecial.invoke(null, doubleToLong.invoke(null, 5e-324)));
+        assertTrue(!(boolean) isSpecial.invoke(null, doubleToLong.invoke(null, -5e-324)));
+        // And some random numbers:
+        assertTrue(!(boolean) isSpecial.invoke(null, doubleToLong.invoke(null, 0.0)));
+        assertTrue(!(boolean) isSpecial.invoke(null, doubleToLong.invoke(null, -0.0)));
+        assertTrue(!(boolean) isSpecial.invoke(null, doubleToLong.invoke(null, 1.0)));
+        assertTrue(!(boolean) isSpecial.invoke(null, doubleToLong.invoke(null, -1.0)));
+        assertTrue(!(boolean) isSpecial.invoke(null, doubleToLong.invoke(null, 1000000.0)));
+        assertTrue(!(boolean) isSpecial.invoke(null, doubleToLong.invoke(null, -1000000.0)));
+        assertTrue(!(boolean) isSpecial.invoke(null, doubleToLong.invoke(null, 1e23)));
+        assertTrue(!(boolean) isSpecial.invoke(null, doubleToLong.invoke(null, -1e23)));
+        assertTrue(!(boolean) isSpecial.invoke(null, doubleToLong.invoke(null, 1.7976931348623157e308)));
+        assertTrue(!(boolean) isSpecial.invoke(null, doubleToLong.invoke(null, -1.7976931348623157e308)));
+    }
+
+        @Test
+    public void testIsInfinite() throws Exception {
+        assertTrue((boolean) isInfinite.invoke(null, doubleToLong.invoke(null, Infinity.invoke(null))));
+        assertTrue((boolean) isInfinite.invoke(null, doubleToLong.invoke(null, -(double) Infinity.invoke(null))));
+        assertTrue(!(boolean) isInfinite.invoke(null, doubleToLong.invoke(null, NaN.invoke(null))));
+        assertTrue(!(boolean) isInfinite.invoke(null, doubleToLong.invoke(null, 0.0)));
+        assertTrue(!(boolean) isInfinite.invoke(null, doubleToLong.invoke(null, -0.0)));
+        assertTrue(!(boolean) isInfinite.invoke(null, doubleToLong.invoke(null, 1.0)));
+        assertTrue(!(boolean) isInfinite.invoke(null, doubleToLong.invoke(null, -1.0)));
+        final long min_double64 = 0x0000000000000001L;
+        assertTrue(!(boolean) isInfinite.invoke(null, min_double64));
+    }
+
+        @Test
+    public void testIsNan() throws Exception {
+        assertTrue((boolean) isNaN.invoke(null, doubleToLong.invoke(null, NaN.invoke(null))));
+        final long other_nan = 0xFFFFFFFF00000001L;
+        assertTrue((boolean) isNaN.invoke(null, other_nan));
+        assertTrue(!(boolean) isNaN.invoke(null, doubleToLong.invoke(null, Infinity.invoke(null))));
+        assertTrue(!(boolean) isNaN.invoke(null, doubleToLong.invoke(null, -(double) Infinity.invoke(null))));
+        assertTrue(!(boolean) isNaN.invoke(null, doubleToLong.invoke(null, 0.0)));
+        assertTrue(!(boolean) isNaN.invoke(null, doubleToLong.invoke(null, -0.0)));
+        assertTrue(!(boolean) isNaN.invoke(null, doubleToLong.invoke(null, 1.0)));
+        assertTrue(!(boolean) isNaN.invoke(null, doubleToLong.invoke(null, -1.0)));
+        final long min_double64 = 0x0000000000000001L;
+        assertTrue(!(boolean) isNaN.invoke(null, min_double64));
+    }
+
+    @Test
+    public void testSign() throws Exception {
+        assertEquals(1, (int) sign.invoke(null, doubleToLong.invoke(null, 1.0)));
+        assertEquals(1, (int) sign.invoke(null, doubleToLong.invoke(null, Infinity.invoke(null))));
+        assertEquals(-1, (int) sign.invoke(null, doubleToLong.invoke(null, -(double) Infinity.invoke(null))));
+        assertEquals(1, (int) sign.invoke(null, doubleToLong.invoke(null, 0.0)));
+        assertEquals(-1, (int) sign.invoke(null, doubleToLong.invoke(null, -0.0)));
+        final long min_double64 = 0x0000000000000001L;
+        assertEquals(1, (int) sign.invoke(null, min_double64));
+    }
+
+    @Test
+    public void testNormalizedBoundaries() throws Exception {
+        Object boundary_plus = DiyFpCtor.newInstance();
+        Object boundary_minus = DiyFpCtor.newInstance();
+        Object diy_fp = asNormalizedDiyFp.invoke(null, doubleToLong.invoke(null, 1.5));
+        normalizedBoundaries.invoke(null, doubleToLong.invoke(null, 1.5), boundary_minus, boundary_plus);
+        assertEquals(e.invoke(diy_fp), e.invoke(boundary_minus));
+        assertEquals(e.invoke(diy_fp), e.invoke(boundary_plus));
+        // 1.5 does not have a significand of the form 2^p (for some p).
+        // Therefore its boundaries are at the same distance.
+        assertTrue((long) f.invoke(diy_fp) - (long) f.invoke(boundary_minus) == (long) f.invoke(boundary_plus) - (long) f.invoke(diy_fp));
+        assertTrue((1 << 10) == (long) f.invoke(diy_fp) - (long) f.invoke(boundary_minus));
+
+        diy_fp =asNormalizedDiyFp.invoke(null, doubleToLong.invoke(null, 1.0));
+        normalizedBoundaries.invoke(null, doubleToLong.invoke(null, 1.0), boundary_minus, boundary_plus);
+        assertEquals(e.invoke(diy_fp), e.invoke(boundary_minus));
+        assertEquals(e.invoke(diy_fp), e.invoke(boundary_plus));
+        // 1.0 does have a significand of the form 2^p (for some p).
+        // Therefore its lower boundary is twice as close as the upper boundary.
+        assertTrue((long) f.invoke(boundary_plus) - (long) f.invoke(diy_fp) > (long) f.invoke(diy_fp) - (long) f.invoke(boundary_minus));
+        assertTrue((1L << 9) == (long) f.invoke(diy_fp) - (long) f.invoke(boundary_minus));
+        assertTrue((1L << 10) == (long) f.invoke(boundary_plus) - (long) f.invoke(diy_fp));
+
+        final long min_double64 = 0x0000000000000001L;
+        diy_fp = asNormalizedDiyFp.invoke(null, min_double64);
+        normalizedBoundaries.invoke(null, min_double64, boundary_minus, boundary_plus);
+        assertEquals(e.invoke(diy_fp), e.invoke(boundary_minus));
+        assertEquals(e.invoke(diy_fp), e.invoke(boundary_plus));
+        // min-value does not have a significand of the form 2^p (for some p).
+        // Therefore its boundaries are at the same distance.
+        assertTrue((long) f.invoke(diy_fp) - (long) f.invoke(boundary_minus) == (long) f.invoke(boundary_plus) - (long) f.invoke(diy_fp));
+        // Denormals have their boundaries much closer.
+        assertTrue(1L << 62 == (long) f.invoke(diy_fp) - (long) f.invoke(boundary_minus));
+
+        final long smallest_normal64 = 0x0010000000000000L;
+        diy_fp = asNormalizedDiyFp.invoke(null, smallest_normal64);
+        normalizedBoundaries.invoke(null, smallest_normal64, boundary_minus, boundary_plus);
+        assertEquals(e.invoke(diy_fp), e.invoke(boundary_minus));
+        assertEquals(e.invoke(diy_fp), e.invoke(boundary_plus));
+        // Even though the significand is of the form 2^p (for some p), its boundaries
+        // are at the same distance. (This is the only exception).
+        assertTrue((long) f.invoke(diy_fp) - (long) f.invoke(boundary_minus) == (long) f.invoke(boundary_plus) - (long) f.invoke(diy_fp));
+        assertTrue(1L << 10 == (long) f.invoke(diy_fp) - (long) f.invoke(boundary_minus));
+
+        final long largest_denormal64 = 0x000FFFFFFFFFFFFFL;
+        diy_fp = asNormalizedDiyFp.invoke(null, largest_denormal64);
+        normalizedBoundaries.invoke(null, largest_denormal64, boundary_minus, boundary_plus);
+        assertEquals(e.invoke(diy_fp),  e.invoke(boundary_minus));
+        assertEquals(e.invoke(diy_fp),  e.invoke(boundary_plus));
+        assertTrue((long) f.invoke(diy_fp) - (long) f.invoke(boundary_minus) == (long) f.invoke(boundary_plus) - (long) f.invoke(diy_fp));
+        assertTrue(1L << 11 == (long) f.invoke(diy_fp) - (long) f.invoke(boundary_minus));
+
+        final long max_double64 = 0x7fefffffffffffffL;
+        diy_fp = asNormalizedDiyFp.invoke(null, max_double64);
+        normalizedBoundaries.invoke(null, max_double64, boundary_minus, boundary_plus);
+        assertEquals(e.invoke(diy_fp),  e.invoke(boundary_minus));
+        assertEquals(e.invoke(diy_fp),  e.invoke(boundary_plus));
+        // max-value does not have a significand of the form 2^p (for some p).
+        // Therefore its boundaries are at the same distance.
+        assertTrue((long) f.invoke(diy_fp) - (long) f.invoke(boundary_minus) == (long) f.invoke(boundary_plus) - (long) f.invoke(diy_fp));
+        assertTrue(1L << 10 == (long) f.invoke(diy_fp) - (long) f.invoke(boundary_minus));
+    }
+
+    @Test
+    public void testNextDouble() throws Exception {
+        assertEquals(4e-324, (double) nextDouble.invoke(null, doubleToLong.invoke(null, 0.0)));
+        assertEquals(0.0, (double) nextDouble.invoke(null, doubleToLong.invoke(null, -0.0)));
+        assertEquals(-0.0, (double) nextDouble.invoke(null, doubleToLong.invoke(null, -4e-324)));
+        assertTrue((int) sign.invoke(null, doubleToLong.invoke(null, nextDouble.invoke(null, doubleToLong.invoke(null, -0.0)))) > 0);
+        assertTrue((int) sign.invoke(null, doubleToLong.invoke(null, nextDouble.invoke(null, doubleToLong.invoke(null, -4e-324)))) < 0);
+        final long d0 = (long) doubleToLong.invoke(null, -4e-324);
+        final long d1 = (long) doubleToLong.invoke(null, nextDouble.invoke(null, d0));
+        final long d2 = (long) doubleToLong.invoke(null, nextDouble.invoke(null, d1));
+        assertEquals(-0.0, value.invoke(null, d1));
+        assertTrue((int) sign.invoke(null, d1) < 0);
+        assertEquals(0.0, value.invoke(null, d2));
+        assertTrue((int) sign.invoke(null, d2) > 0);
+        assertEquals(4e-324, (double) nextDouble.invoke(null, d2));
+        assertEquals(-1.7976931348623157e308, (double) nextDouble.invoke(null, doubleToLong.invoke(null, -(double) Infinity.invoke(null))));
+        assertEquals(Infinity.invoke(null), (double) nextDouble.invoke(null, 0x7fefffffffffffffL));
+    }
+
+    @Test
+    public void testPreviousDouble() throws Exception {
+        assertEquals(0.0, (double) previousDouble.invoke(null, doubleToLong.invoke(null, 4e-324)));
+        assertEquals(-0.0, (double) previousDouble.invoke(null, doubleToLong.invoke(null, 0.0)));
+        assertTrue((int) sign.invoke(null, doubleToLong.invoke(null, previousDouble.invoke(null, doubleToLong.invoke(null, 0.0)))) < 0);
+        assertEquals(-4e-324, previousDouble.invoke(null, doubleToLong.invoke(null, -0.0)));
+        final long d0 = (long) doubleToLong.invoke(null, 4e-324);
+        final long d1 = (long) doubleToLong.invoke(null, previousDouble.invoke(null, d0));
+        final long d2 = (long) doubleToLong.invoke(null, previousDouble.invoke(null, d1));
+        assertEquals(0.0, value.invoke(null, d1));
+        assertTrue((int) sign.invoke(null, d1) > 0);
+        assertEquals(-0.0, value.invoke(null, d2));
+        assertTrue((int) sign.invoke(null, d2) < 0);
+        assertEquals(-4e-324, (double) previousDouble.invoke(null, d2));
+        assertEquals(1.7976931348623157e308, (double) previousDouble.invoke(null, doubleToLong.invoke(null, Infinity.invoke(null))));
+        assertEquals(-(double) Infinity.invoke(null), (double) previousDouble.invoke(null, 0xffefffffffffffffL));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/src/jdk/nashorn/internal/runtime/doubleconv/test/resources/gay-fixed.txt	Wed Nov 11 15:22:14 2015 +0100
@@ -0,0 +1,100059 @@
+// Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+//
+// This code is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License version 2 only, as
+// published by the Free Software Foundation.  Oracle designates this
+// particular file as subject to the "Classpath" exception as provided
+// by Oracle in the LICENSE file that accompanied this code.
+//
+// This code is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// version 2 for more details (a copy is included in the LICENSE file that
+// accompanied this code).
+//
+// You should have received a copy of the GNU General Public License version
+// 2 along with this work; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+// or visit www.oracle.com if you need additional information or have any
+// questions.
+
+// This file is available under and governed by the GNU General Public
+// License version 2 only, as published by the Free Software Foundation.
+// However, the following notice accompanied the original version of this
+// file:
+//
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This file contains 100.000 decimal representations of random doubles. They
+// have been generated using Gay's dtoa to produce the fixed representation:
+//         dtoa(v, 3, number_digits, &decimal_point, &sign, NULL);
+
+3.3831671815188012695312500e+12, 2, "33831671815188", 13
+6.6336520115995179509212087e-08, 13, "663365", -7
+9.5272682545672953764716918e-12, 12, "1", -10
+4.9841402988132226055635983e-17, 18, "5", -16
+5.5567065195971976208966225e+04, 10, "55567065195972", 5
+4.9104496948979206577675857e-06, 16, "49104496949", -5
+3.3201849526148178100585938e+10, 15, "33201849526148178100585938", 11
+1.0763823300509811087977141e+05, 5, "10763823301", 6
+5.7566658010014374078778435e-21, 7, "", -7
+4.4522053704113441692420585e-22, 11, "", -11
+2.9987655603737279307097197e+05, 7, "2998765560374", 6
+4.8003206570135421886612002e-22, 2, "", -2
+3.5264274092038518750000000e+14, 3, "352642740920385188", 15
+1.7950381905756516482839877e-06, 5, "", -5
+1.5223827362137477393844165e+04, 19, "152238273621374773938442", 5
+6.9000318153219332254467145e-25, 0, "", 0
+1.7189048239317447630547520e-01, 17, "17189048239317448", 0
+6.3839563615044511854648590e+07, 12, "63839563615044511855", 8
+9.1193616301674545152000000e+19, 0, "91193616301674545152", 20
+3.8742733030609424531576224e+03, 14, "387427330306094245", 4
+2.9632075676930808341943013e-16, 13, "", -13
+1.0214690802570292136458585e-03, 1, "", -1
+1.2002490160553595699200000e+20, 11, "120024901605535956992", 21
+1.2532714671596547392068421e-03, 15, "125327146716", -2
+5.5607379380725792307349389e-18, 6, "", -6
+1.0906117333419780000000000e+16, 18, "1090611733341978", 17
+2.5283417241664493934893199e-22, 6, "", -6
+3.6174597185439385817340239e-12, 5, "", -5
+2.7264001074276206986698439e-16, 18, "273", -15
+5.4516442391198194827293386e-23, 11, "", -11
+3.7960824607766062761653904e-12, 10, "", -10
+3.9237910537314860871315020e-20, 11, "", -11
+7.5599098753701514521530572e-06, 10, "75599", -5
+9.5479706420957142967015363e-05, 2, "", -2
+2.2408351583231838149748279e-12, 0, "", 0
+2.1213945654234204503946545e-14, 5, "", -5
+3.0134079464150507428592409e-25, 20, "", -20
+5.4040956719115788800000000e+17, 10, "540409567191157888", 18
+1.9473073693308637605405601e-10, 16, "1947307", -9
+4.1501939700379796326160431e+07, 6, "4150193970038", 8
+3.4608659167475043332007356e-05, 10, "346087", -4
+2.8901046914596528529214133e-06, 11, "28901", -5
+2.2917399895460568631695837e-24, 4, "", -4
+1.4190629332123970380052924e+05, 2, "14190629", 6
+3.5270798938471071464452046e-24, 7, "", -7
+1.4206078795880712000000000e+17, 8, "14206078795880712", 18
+4.5281297678439813120000000e+18, 6, "4528129767843981312", 19
+3.1224513642477845954022186e-05, 10, "312245", -4
+4.8184662102767651659096515e-04, 19, "4818466210276765", -3
+2.3994634581213830680848642e-05, 5, "2", -4
+8.8542098092391940955536711e-02, 18, "88542098092391941", -1
+5.3723698087028667187200000e+20, 18, "537236980870286671872", 21
+1.4124481890311051874892408e-05, 13, "141244819", -4
+1.2560868646257232157234815e-08, 2, "", -2
+3.2969008954989711360000000e+18, 3, "3296900895498971136", 19
+1.2897899252746862617333836e-11, 14, "129", -10
+1.5851808323022507871829358e-24, 18, "", -18
+3.6044438440996938152238727e+05, 13, "3604443844099693815", 6
+7.3834019095011149680374274e-01, 15, "738340190950111", 0
+1.8534457765231180800000000e+18, 0, "185344577652311808", 19
+1.3036086798096085555602984e-14, 5, "", -5
+6.8366806754097264640000000e+18, 20, "6836680675409726464", 19
+1.8097184247068291443049085e-09, 6, "", -6
+1.7217755406130052309794443e-15, 20, "172178", -14
+3.5882578140235449704223259e-24, 15, "", -15
+6.1335653680739776000000000e+17, 17, "61335653680739776", 18
+9.1022946537954569986230862e-21, 8, "", -8
+7.3131970558145258110016584e+04, 7, "731319705581", 5
+1.2113449620203359309629696e-25, 12, "", -12
+1.5798859598969343664975895e+00, 3, "158", 1
+5.0813068520260342252731732e-06, 4, "", -4
+1.2542380640419709108825076e-06, 1, "", -1
+2.5234102601179311991432374e-17, 1, "", -1
+1.4121549845416071987200000e+20, 6, "141215498454160719872", 21
+4.7882613737425489100800000e+20, 15, "478826137374254891008", 21
+2.1626350759996771761862586e-17, 11, "", -11
+1.6414006087460717431270041e+00, 19, "16414006087460717431", 1
+4.5361128636816219539998116e-23, 3, "", -3
+7.2735863867313000000000000e+15, 17, "72735863867313", 16
+8.0304628746085993107328704e-01, 17, "80304628746085993", 0
+1.7635161128880073550274639e-07, 0, "", 0
+2.6595496455345386813597399e-11, 12, "27", -10
+2.4101037841260125248068991e-17, 15, "", -15
+4.1107717582186380237048047e-13, 10, "", -10
+8.8995580590833796406736514e-19, 4, "", -4
+2.0914671392174199127111933e+01, 11, "2091467139217", 2
+2.0009613495402837554659747e-03, 15, "200096134954", -2
+1.6938779113170488939078514e-16, 2, "", -2
+5.8952117497404695312500000e+13, 19, "589521174974046953125", 14
+3.8570274835217771530151367e+09, 20, "385702748352177715301513671875", 10
+4.1471840195422703017086694e-13, 5, "", -5
+2.0993395069684979772905997e-03, 13, "2099339507", -2
+5.5766955004207104679172822e-09, 7, "", -7
+6.6931607225485343951731920e+05, 14, "66931607225485343952", 6
+1.6032543002557476856541661e-18, 13, "", -13
+1.0952163279330218159657306e-01, 4, "1095", 0
+5.9115686770881026983261108e+07, 4, "591156867709", 8
+1.4611977142167729581956337e+01, 19, "14611977142167729582", 2
+1.8403884352113170755887048e-17, 7, "", -7
+6.1593329939462579200000000e+17, 8, "615933299394625792", 18
+5.7047053101680171489715576e+08, 4, "5704705310168", 9
+1.3261286743920106000000000e+16, 4, "13261286743920106", 17
+1.0929164126882341537645069e-24, 12, "", -12
+7.6140695873445726203974923e-25, 4, "", -4
+8.4354388134942532717116778e-19, 13, "", -13
+1.7705045161451824844582371e-10, 12, "177", -9
+1.4880751226717142051628936e-21, 9, "", -9
+1.3964327111550966789292362e-14, 7, "", -7
+2.2144802189819714523244532e-03, 18, "2214480218981971", -2
+9.5948768656345468480139971e+05, 6, "959487686563", 6
+1.2503288376063125042492175e+02, 17, "12503288376063125042", 3
+3.9972488070634699941496848e-03, 1, "", -1
+4.7255968912832667375282580e-14, 2, "", -2
+1.1299384774525735863903719e+00, 9, "1129938477", 1
+9.2628617333939845629077729e-10, 0, "", 0
+5.9858471663241181928011292e-04, 13, "5985847166", -3
+1.2463762619502296356500913e-19, 14, "", -14
+1.0680175344129960983991623e+07, 8, "1068017534412996", 8
+5.4352221854741964489221573e+06, 16, "54352221854741964489222", 7
+1.9305774853762348910422960e-25, 4, "", -4
+1.3213268824321876312297703e-11, 10, "", -10
+5.2640143935748890000000000e+15, 9, "5264014393574889", 16
+6.6142638526627683639526367e+08, 18, "661426385266276836395263672", 9
+3.1368662210752113342285156e+10, 18, "3136866221075211334228515625", 11
+1.1582551737676625920000000e+18, 6, "1158255173767662592", 19
+1.6254431310797307904000000e+19, 1, "16254431310797307904", 20
+5.7862282353719001154294943e-05, 6, "58", -4
+2.0169260185533577500000000e+15, 10, "201692601855335775", 16
+9.4052052008856257445284494e-25, 15, "", -15
+1.2642910662179308864459630e-05, 10, "126429", -4
+1.4507307446793091366998851e+05, 3, "145073074", 6
+1.3561940461288199519162671e-11, 10, "", -10
+7.0141472478594906192483904e+01, 3, "70141", 2
+1.4424311556076677500000000e+15, 2, "144243115560766775", 16
+2.6624630288203108768104088e-17, 2, "", -2
+1.9672898210650612792968750e+12, 10, "19672898210650612792969", 13
+6.0451363370732295152265579e+04, 18, "60451363370732295152266", 5
+2.0221778386268979624262876e-04, 18, "20221778386269", -3
+3.3373938250735634937882423e+05, 16, "3337393825073563493788", 6
+1.7118396920196160678281526e-06, 7, "17", -5
+6.6182791405781114008277655e+05, 14, "66182791405781114008", 6
+1.0045733935141063309630930e-07, 13, "1004573", -6
+1.0116919511705794199623708e-25, 2, "", -2
+3.4004358044233266854282968e-06, 9, "34", -5
+5.2617685342884970703125000e+12, 11, "52617685342884970703125", 13
+6.4921701091538345610920186e-09, 15, "649217", -8
+2.5778852871242243410864273e-05, 0, "", 0
+2.8246582215737890518550396e-10, 10, "3", -9
+1.5135758529656283258158617e-07, 7, "2", -6
+1.3343025399887900774365890e-20, 3, "", -3
+2.8278155616716954880284878e-11, 1, "", -1
+5.6378829490276199942755397e-02, 0, "", 0
+1.2868269024563838266408552e-25, 0, "", 0
+3.6166256007503268750000000e+14, 14, "3616625600750326875", 15
+1.2928764000372916052583605e+05, 13, "1292876400037291605", 6
+1.0676395469783407500000000e+15, 5, "106763954697834075", 16
+4.9954954330023173270092229e+02, 20, "49954954330023173270092", 3
+4.6444597190569909409139053e-11, 16, "464446", -10
+1.5480660915963378491890141e-06, 6, "2", -5
+1.4514592337731665000000000e+15, 13, "14514592337731665", 16
+4.0505605256757553710937500e+12, 5, "405056052567575537", 13
+6.3806276212447906494140625e+10, 11, "6380627621244790649414", 11
+6.8553398114291289062500000e+13, 20, "685533981142912890625", 14
+1.9031459984169772949218750e+12, 3, "1903145998416977", 13
+2.0874315309021840213311050e-22, 6, "", -6
+1.9692844090873872397466595e-10, 1, "", -1
+3.8893196328943255000000000e+15, 14, "38893196328943255", 16
+9.8324604625011558532714844e+09, 20, "9832460462501155853271484375", 10
+2.8771219339319028222234920e+04, 10, "28771219339319", 5
+7.3457474264623248000000000e+16, 10, "73457474264623248", 17
+3.7273775361248293658978065e-11, 12, "37", -10
+2.9130692671725196305487771e+03, 20, "291306926717251963054878", 4
+1.6431834096448312276805837e+00, 14, "164318340964483", 1
+4.9356541931380421417032509e-17, 18, "49", -16
+4.2731741486511391401290894e+08, 19, "4273174148651139140129089355", 9
+8.4546040861937177734375000e+12, 13, "84546040861937177734375", 13
+1.2951736554037045316689908e-14, 10, "", -10
+8.9771194677615917968750000e+11, 7, "8977119467761591797", 12
+5.3226887919510871134643956e-06, 6, "5", -5
+1.4207285173359171630567012e-16, 9, "", -9
+6.3787190685416415333747864e+07, 20, "6378719068541641533374786377", 8
+2.1888004928833254238427763e-09, 6, "", -6
+7.4145695027005315913048512e-08, 17, "7414569503", -7
+6.3774948173026490585399991e-25, 2, "", -2
+2.4649784218832827775713668e+01, 2, "2465", 2
+4.3941934218409529600000000e+17, 16, "439419342184095296", 18
+2.7985286096439249863339367e-20, 20, "3", -19
+1.1402300461518555323025160e-07, 18, "114023004615", -6
+1.2210797779666126428462330e-20, 1, "", -1
+3.2467848990623744000000000e+19, 15, "32467848990623744", 20
+1.8002495001504619231980087e+00, 20, "18002495001504619232", 1
+8.9936094972024887500000000e+14, 14, "899360949720248875", 15
+7.2990991639792275303146894e-13, 19, "7299099", -12
+6.1424251973058772992000000e+19, 6, "61424251973058772992", 20
+3.0991608445670382812500000e+13, 19, "309916084456703828125", 14
+3.6834034437956632153208939e-07, 6, "", -6
+1.0501779976355870737446294e-16, 14, "", -14
+7.3140995548782427210832664e-09, 8, "1", -7
+1.3813354552642654400000000e+17, 2, "138133545526426544", 18
+1.0142048016450877102923291e-23, 4, "", -4
+6.5438725968370177979272920e-13, 19, "6543873", -12
+3.6967369327857186201563566e-04, 16, "3696736932786", -3
+7.2828404557714341888000000e+19, 15, "72828404557714341888", 20
+1.2212108055027883911132812e+11, 13, "1221210805502788391113281", 12
+1.3401053941016547454978536e+01, 7, "134010539", 2
+2.1724905024900357033978970e-03, 18, "2172490502490036", -2
+8.0803951093300856882706285e+03, 19, "80803951093300856882706", 4
+4.5969500923253701785142766e+02, 15, "459695009232537018", 3
+1.3868155087243519045843509e-14, 15, "14", -13
+1.2359729902963124166802604e-07, 8, "12", -6
+1.5818447566466890595682600e-19, 8, "", -8
+4.7651086083820712381173263e-13, 8, "", -8
+7.3969147645907158203125000e+12, 2, "739691476459072", 13
+2.1188426160157262500000000e+15, 3, "211884261601572625", 16
+6.8529487180597614681687446e+00, 10, "68529487181", 1
+2.0660268075938550604549156e-09, 2, "", -2
+1.3433242572017365811200000e+20, 12, "134332425720173658112", 21
+2.9002890347293918327623241e-17, 17, "3", -16
+1.1279459380144599869603835e-16, 4, "", -4
+2.1070726795590904355049133e+08, 19, "210707267955909043550491333", 9
+7.5267764089994978904724121e+08, 2, "7526776409", 9
+3.6097454332913807360000000e+19, 7, "3609745433291380736", 20
+5.2926805003219556944316082e-01, 16, "5292680500321956", 0
+8.9363677329360468191263078e-09, 9, "9", -8
+2.8222931466159600116107255e-22, 20, "", -20
+1.4546040920223487765022797e-20, 13, "", -13
+1.8589410713265433739182569e-11, 7, "", -7
+1.2084295498025406701003703e+01, 12, "12084295498025", 2
+4.3401521679778678475258857e+00, 5, "434015", 1
+4.2852574152516575978211222e-01, 16, "4285257415251658", 0
+1.1260860143722513071235979e-09, 1, "", -1
+2.9167677798337560576000000e+20, 15, "29167677798337560576", 21
+4.4272500418027791267737559e-25, 11, "", -11
+8.3947115097384701768623167e-21, 4, "", -4
+1.0343380279944637644800000e+20, 5, "103433802799446376448", 21
+6.5402105087171250374922238e+01, 17, "6540210508717125037", 2
+3.1025406722371033538365737e+04, 15, "31025406722371033538", 5
+5.3963389836780800000000000e+18, 13, "539633898367808", 19
+2.1795959610932865235213848e-18, 8, "", -8
+6.2167530047603133425582200e+04, 7, "621675300476", 5
+2.0818189944930562048000000e+19, 7, "20818189944930562048", 20
+1.1334484383814122766011686e-13, 8, "", -8
+3.5405135100601997274390662e-15, 20, "354051", -14
+1.0968314815521232330475243e-01, 17, "10968314815521232", 0
+9.0383771555964514160156250e+11, 13, "9038377155596451416015625", 12
+1.2510522082259552105145731e-23, 1, "", -1
+9.9544404864834694188658205e-22, 1, "", -1
+5.0628146207835304085165262e+05, 18, "506281462078353040851653", 6
+1.1186933259374121005921885e-13, 9, "", -9
+1.0976726590655720000000000e+17, 14, "1097672659065572", 18
+2.8022216332446113586425781e+10, 12, "28022216332446113586426", 11
+7.1934307994897493967930029e-25, 5, "", -5
+5.5291432217254227281902864e-09, 4, "", -4
+1.1929516930900315745297508e-11, 4, "", -4
+7.6108877727559904000000000e+16, 19, "76108877727559904", 17
+1.5016564647649209976196289e+10, 3, "15016564647649", 11
+1.6066177601408008014525277e-25, 14, "", -14
+6.1618894565902694400000000e+18, 8, "616188945659026944", 19
+5.3562535282045684644630645e-05, 12, "53562535", -4
+1.3489031213176578703251586e-20, 16, "", -16
+1.5711695240513652152003488e+03, 4, "15711695", 4
+2.5122660050106903125000000e+14, 12, "25122660050106903125", 15
+2.0221030889363189945918116e-25, 11, "", -11
+1.1303024599909523925781250e+12, 8, "113030245999095239258", 13
+2.7903529772880277282470497e-17, 13, "", -13
+2.5121592915444268000000000e+16, 12, "25121592915444268", 17
+1.8048932996675591037873237e-12, 9, "", -9
+3.2226438096721920967102051e+09, 19, "32226438096721920967102050781", 10
+3.5147466372419680000000000e+16, 5, "3514746637241968", 17
+9.0135298952772956382880432e-18, 2, "", -2
+6.3266457307088434696197510e+07, 19, "632664573070884346961975098", 8
+1.4406496436364404507912695e+05, 9, "144064964363644", 6
+1.4048067471615732259952259e-14, 10, "", -10
+2.9319085253905223680000000e+19, 20, "2931908525390522368", 20
+1.3329477284912236366235759e-14, 0, "", 0
+1.7026555641068125000000000e+12, 12, "17026555641068125", 13
+8.2651115310402929687500000e+11, 16, "826511153104029296875", 12
+5.5492375565887810020337740e-11, 20, "5549237557", -10
+5.2100294487580758868716657e+03, 7, "52100294488", 4
+4.0139643139973952168422826e-10, 1, "", -1
+2.8674611869754667816843301e-22, 0, "", 0
+1.0453866711057700000000000e+16, 17, "104538667110577", 17
+3.5532073414203446399733964e-21, 10, "", -10
+2.8981256166572560661301612e-06, 20, "289812561665726", -5
+2.7486824389362219721078873e+07, 1, "274868244", 8
+3.6201696821935169435256875e-22, 16, "", -16
+2.8058107970984572602901608e+04, 2, "2805811", 5
+8.8321877347744512500000000e+14, 19, "883218773477445125", 15
+2.2155126434192637952000000e+20, 8, "22155126434192637952", 21
+5.1567392078515772332434909e-19, 10, "", -10
+5.0513022116504699707031250e+11, 10, "5051302211650469970703", 12
+3.7597560279127286803917860e-10, 8, "", -8
+1.9918607403922733798466954e-08, 16, "199186074", -7
+4.4234861458519274112308677e-11, 9, "", -9
+1.9023164229540652612705182e-23, 8, "", -8
+7.1021989711764663835586035e-17, 0, "", 0
+3.6661956748787194459993088e-03, 11, "366619567", -2
+4.9881566722141451464267448e+03, 6, "4988156672", 4
+4.4707644314334054706349725e-18, 14, "", -14
+5.4215846449332083523131587e+01, 7, "542158464", 2
+8.6593847936715371093750000e+12, 20, "8659384793671537109375", 13
+8.9829444141474144158342862e-13, 4, "", -4
+1.2428552364439995936840696e-23, 6, "", -6
+2.0166248952875683020800000e+20, 14, "201662489528756830208", 21
+3.7327184170362130051641231e-10, 3, "", -3
+1.9396181842743126511052765e-01, 10, "1939618184", 0
+3.5826922897186040000000000e+15, 3, "3582692289718604", 16
+2.7997315854645470000000000e+15, 14, "2799731585464547", 16
+1.1716597516408188382752709e-03, 11, "117165975", -2
+6.1882081648340598286333083e-12, 6, "", -6
+4.7370998762520938329956266e-01, 14, "47370998762521", 0
+4.4423933102435251285555751e+00, 6, "4442393", 1
+2.4957876235100876254256602e-13, 2, "", -2
+4.9401969802917692648337084e-21, 12, "", -12
+4.2151799896157845246123103e-05, 11, "421518", -4
+2.4330919434329737782718439e+02, 10, "2433091943433", 3
+3.9704848760294156174359833e-12, 6, "", -6
+6.5113509688550708007812500e+11, 9, "651135096885507080078", 12
+2.0201107491561449606421665e-23, 6, "", -6
+2.6003917513806278638625986e-23, 5, "", -5
+5.0313319321305721556240123e-20, 4, "", -4
+1.9240049601829819039267022e+03, 1, "1924", 4
+6.3442694622108669906036630e-19, 8, "", -8
+2.0557491959316193970153108e+03, 19, "20557491959316193970153", 4
+1.4668421724264454678632319e+05, 5, "14668421724", 6
+3.1382428850300479739043880e-02, 16, "313824288503005", -1
+1.5369430639587627812077865e-25, 4, "", -4
+3.4450899741885118216139212e-23, 10, "", -10
+3.0911588760980589389647070e-06, 14, "309115888", -5
+5.9404363317825529446400000e+20, 16, "594043633178255294464", 21
+1.0857475716345135636849922e-19, 20, "11", -18
+3.8383232743368286832286174e-03, 13, "38383232743", -2
+1.4248749471152849662394563e-24, 2, "", -2
+2.0089993582817679967922331e-03, 0, "", 0
+3.5166231882836703125000000e+13, 19, "35166231882836703125", 14
+1.7140450352925487923200000e+20, 4, "171404503529254879232", 21
+3.2313165658527839975219013e-12, 11, "", -11
+1.3290330898952539062500000e+12, 8, "132903308989525390625", 13
+2.0158316345631235866342479e-01, 11, "20158316346", 0
+2.0251250657297560785223673e-17, 9, "", -9
+3.5216352032369835037977929e-06, 12, "3521635", -5
+1.5477908597039305438336498e-01, 15, "154779085970393", 0
+3.8765938532090029581303166e-07, 0, "", 0
+3.2509338468973143939918862e-08, 13, "325093", -7
+6.2581518574031498426888197e-22, 1, "", -1
+5.0432161912984668742865324e+05, 7, "5043216191298", 6
+9.6059655990911452239089385e-01, 2, "96", 0
+1.1244083027408466250000000e+15, 5, "1124408302740846625", 16
+5.3601666644035825729370117e+09, 3, "5360166664404", 10
+3.3127818916477214545011520e+07, 1, "331278189", 8
+2.4908086930109192280724528e+02, 13, "2490808693010919", 3
+3.4779094857233305848609461e-01, 11, "34779094857", 0
+3.3572755934667378664016724e+08, 4, "3357275593467", 9
+1.9700038127631859585015404e-23, 20, "", -20
+7.0715094103144121510498532e-10, 10, "7", -9
+6.7037630116271845703125000e+12, 7, "67037630116271845703", 13
+1.1294460364897787094116211e+10, 10, "112944603648977870941", 11
+2.6737449213299253902593328e-06, 20, "267374492132993", -5
+1.5092206282517178280423561e-25, 13, "", -13
+3.4006989646044941122404737e-02, 3, "34", -1
+2.8111487221637728326893389e-13, 18, "281115", -12
+3.3781298583464045000000000e+15, 19, "33781298583464045", 16
+2.0016679896775639040000000e+18, 15, "2001667989677563904", 19
+1.4597094942281232769765165e-05, 10, "145971", -4
+4.8414051366454500000000000e+15, 4, "484140513664545", 16
+1.7739354377277198433876038e+08, 16, "1773935437727719843387604", 9
+3.7697954983919595682092819e-08, 12, "37698", -7
+8.4591744140055547662350276e-23, 8, "", -8
+1.6701760624616502669922589e-07, 0, "", 0
+4.5469943845790237188339233e+08, 18, "454699438457902371883392334", 9
+1.4754293744614287109375000e+13, 8, "1475429374461428710938", 14
+1.4963498919564651844921199e-03, 8, "149635", -2
+7.6466410401813972493203345e-13, 3, "", -3
+4.2381940527961081766968194e-20, 8, "", -8
+6.2854523843617129348328318e-18, 17, "1", -16
+1.2737541989685046552542302e-19, 19, "1", -18
+4.6196666564184898138046265e+08, 16, "4619666656418489813804626", 9
+2.8953766720828063744000000e+19, 11, "28953766720828063744", 20
+1.0162813924779992000000000e+16, 8, "10162813924779992", 17
+1.9599596534796953457442637e-07, 7, "2", -6
+8.3021846385465843200000000e+17, 7, "830218463854658432", 18
+1.4624248110616019900782450e-08, 5, "", -5
+1.2715287496333471679687500e+11, 2, "12715287496333", 12
+6.8027550113978083805126029e-05, 8, "6803", -4
+1.0981062031294560432434082e+09, 14, "109810620312945604324341", 10
+1.0734438619766858537036273e-22, 13, "", -13
+1.4132567191936884075403214e+07, 13, "141325671919368840754", 8
+1.5904224504531770518546239e-19, 0, "", 0
+2.4535972468695058101850748e-02, 16, "245359724686951", -1
+1.5601068380432108719197678e-25, 9, "", -9
+9.4978590368356121600000000e+17, 15, "949785903683561216", 18
+2.0706122814619420482871761e-18, 11, "", -11
+1.1526018485517715308715826e-05, 3, "", -3
+6.2402039265004006238472082e-22, 20, "", -20
+1.2145622298653942217061541e-01, 4, "1215", 0
+3.1360207022830924383576760e-06, 1, "", -1
+2.0903682178737230401566194e+02, 4, "2090368", 3
+6.8236005557543791873404286e-09, 20, "682360055575", -8
+1.1601601555390701105352491e+05, 1, "116016", 6
+2.1875218169481468882819897e-02, 8, "2187522", -1
+4.5972064065543524858311040e-12, 1, "", -1
+6.2553419557858422851562500e+11, 16, "625534195578584228515625", 12
+3.2966393741860024414062500e+12, 6, "3296639374186002441", 13
+5.6680567511992276576782010e-23, 14, "", -14
+1.2468383853738613900888840e-09, 2, "", -2
+1.3516183239875930940931958e-02, 17, "1351618323987593", -1
+1.4629096926763364422947094e-10, 2, "", -2
+9.3005408780297322664409876e+05, 15, "930054087802973226644", 6
+1.1529918172478498816000000e+19, 11, "11529918172478498816", 20
+4.1294372464822801449272813e-09, 8, "", -8
+1.0652815658147843150223105e-14, 12, "", -12
+1.0635569818699313327670097e+07, 18, "10635569818699313327670097", 8
+3.7580988683046307414770126e+05, 12, "375809886830463074", 6
+4.5857820827792426143787452e+02, 17, "45857820827792426144", 3
+2.9212956460630989568016957e+03, 1, "29213", 4
+2.6276323897159130000000000e+15, 1, "2627632389715913", 16
+2.7576598371538500178642983e-04, 9, "275766", -3
+1.8156829540410031250000000e+13, 20, "1815682954041003125", 14
+6.0690729978642972672000000e+19, 4, "60690729978642972672", 20
+2.1545222814755082725630899e-19, 20, "22", -18
+6.2024521141395034707240936e-18, 18, "6", -17
+2.4396751930476269531250000e+11, 3, "243967519304763", 12
+3.1078669709725926955610271e-11, 20, "3107866971", -10
+8.1545725581179377232175041e-13, 5, "", -5
+1.1618790914057837871226501e-18, 20, "116", -17
+2.6046821088380256174972241e-17, 14, "", -14
+2.8418526195341197312000000e+20, 15, "28418526195341197312", 21
+4.5585073586198306250000000e+14, 12, "4558507358619830625", 15
+5.0996252363668905359535798e-06, 14, "509962524", -5
+6.4209197762026025390625000e+12, 15, "64209197762026025390625", 13
+6.1386540264423591613769531e+10, 2, "6138654026442", 11
+1.5901378535836493167727811e-22, 16, "", -16
+5.4579315266585999779636040e+03, 9, "5457931526659", 4
+1.2544567961879360724719261e-19, 13, "", -13
+1.5726122819958073548134890e-10, 3, "", -3
+6.7892777701670213325729764e-04, 16, "6789277770167", -3
+1.4169809676321635923737215e-22, 2, "", -2
+6.5176922380697329664000000e+19, 20, "65176922380697329664", 20
+5.5595451528948190748782970e-14, 1, "", -1
+2.9557912637578951944306027e+03, 6, "2955791264", 4
+7.2804775134548956743238107e-14, 6, "", -6
+4.1622415121078927313647000e+02, 3, "416224", 3
+4.8737064570386013429015293e+02, 17, "48737064570386013429", 3
+1.7498415755518933164186024e-06, 7, "17", -5
+2.2160805224873369729673253e-17, 8, "", -8
+9.9265578616519537168307897e-12, 6, "", -6
+6.6758215277996143860236308e-12, 16, "66758", -11
+5.1455371830973781754892116e+01, 0, "51", 2
+2.3075746794683029187132683e-04, 14, "23075746795", -3
+6.4945848324870469859236566e-08, 3, "", -3
+6.0802847387444488704204559e+06, 17, "608028473874444887042046", 7
+4.4425197752128814387972966e-01, 1, "4", 0
+1.4934964441781190132421138e-11, 12, "15", -10
+2.4031131480610081752047336e+01, 16, "240311314806100818", 2
+8.3281476308039543710037833e+01, 1, "833", 2
+8.1973746018195646706808177e-05, 11, "8197375", -4
+4.3535772344454751873854548e+04, 16, "435357723444547518739", 5
+2.8755564450912231250000000e+14, 10, "2875556445091223125", 15
+4.4918701600850165899382182e-07, 1, "", -1
+2.6366858934475584419487859e+02, 14, "26366858934475584", 3
+5.1431268805072780800000000e+17, 1, "514312688050727808", 18
+8.8938194097586913280000000e+19, 14, "8893819409758691328", 20
+8.0147414624415674211377336e+01, 14, "8014741462441567", 2
+1.2879068417818787500000000e+15, 10, "128790684178187875", 16
+2.2218672530926345643820241e+04, 11, "2221867253092635", 5
+3.1017827311573439836502075e+08, 16, "3101782731157343983650208", 9
+4.6805104189323446917114779e+02, 12, "468051041893234", 3
+1.0556482317454627685546875e+12, 11, "105564823174546276855469", 13
+2.3913654765548638999462128e+07, 19, "239136547655486389994621277", 8
+1.1925126244955090805888176e+07, 10, "119251262449550908", 8
+1.0833732148616976737976074e+09, 15, "1083373214861697673797607", 10
+1.1287157303072798000000000e+16, 2, "11287157303072798", 17
+1.0362533438151604633600000e+20, 5, "103625334381516046336", 21
+7.2161202121139090000000000e+15, 4, "7216120212113909", 16
+2.5346680067095468984916806e+05, 3, "253466801", 6
+8.9627245238208430080000000e+18, 14, "8962724523820843008", 19
+2.3665350448230400085449219e+09, 18, "2366535044823040008544921875", 10
+1.2374610579226049367207452e+02, 6, "123746106", 3
+3.5448098652618561945600000e+20, 17, "354480986526185619456", 21
+2.5817473351112571435805876e+03, 5, "258174734", 4
+4.5546401398805186344631579e-01, 8, "45546401", 0
+1.2914906099985468316280681e-10, 13, "1291", -9
+5.1813111936968350410461426e+08, 5, "51813111936968", 9
+2.8751314218348569869995117e+09, 3, "2875131421835", 10
+6.7538805627191125791064508e-02, 10, "675388056", -1
+4.2316070478339520377630834e+02, 1, "4232", 3
+3.0755848678420653343200684e+09, 4, "30755848678421", 10
+8.9311194754829756448089029e+01, 19, "893111947548297564481", 2
+2.5635322913220988000000000e+16, 15, "25635322913220988", 17
+5.1344959677535087500000000e+14, 20, "513449596775350875", 15
+4.5481702647512625148351617e+00, 7, "45481703", 1
+4.0198903458776960000000000e+16, 13, "4019890345877696", 17
+3.0620773098517361371362355e-02, 15, "30620773098517", -1
+1.7845519018708885111924403e-17, 8, "", -8
+5.3036536346217483511161772e-04, 19, "5303653634621748", -3
+1.7089428267341041922655620e-02, 10, "170894283", -1
+1.5807414247286351562500000e+13, 1, "158074142472864", 14
+2.4002650960294847438489863e-19, 1, "", -1
+1.2732752944365720358124801e-24, 3, "", -3
+1.7831984146947735552000000e+19, 10, "17831984146947735552", 20
+1.3809582421010034838569465e-14, 7, "", -7
+7.9343878040550280761718750e+11, 4, "7934387804055028", 12
+1.7277451890719719511506527e-16, 7, "", -7
+8.0903795948917157910679201e-11, 0, "", 0
+1.6637015661079619174400000e+20, 17, "166370156610796191744", 21
+3.0740431082850804164085363e-19, 1, "", -1
+3.3365763449652551560662869e-16, 16, "3", -15
+4.4683629156000673735353676e-13, 11, "", -11
+6.5678354263822395946548181e-17, 8, "", -8
+1.0244415058360816452487536e-06, 0, "", 0
+8.9199577753000795767914271e-13, 3, "", -3
+7.7002722543322809206210042e-23, 16, "", -16
+3.8537044548224612254337059e-25, 3, "", -3
+4.3809531541275278071484210e-11, 20, "4380953154", -10
+6.0548416510883020240867685e-14, 12, "", -12
+5.8513966989801442396445652e-15, 10, "", -10
+9.4441417174617753879094542e-18, 14, "", -14
+1.7150618308992182272000000e+19, 1, "17150618308992182272", 20
+4.6590061150223489676136523e+04, 15, "46590061150223489676", 5
+2.3991155984836840154823923e-11, 18, "23991156", -10
+1.1693714649575429687500000e+12, 18, "116937146495754296875", 13
+5.3142513230907159442262267e-12, 7, "", -7
+2.6234513296017294682429595e-20, 5, "", -5
+1.6775188267406185294028376e-01, 4, "1678", 0
+2.0545325166979831250000000e+14, 7, "2054532516697983125", 15
+2.3477850437737580800000000e+17, 5, "234778504377375808", 18
+1.6746562547338615587523725e-13, 14, "17", -12
+3.1992844795375771484375000e+12, 19, "31992844795375771484375", 13
+1.6322309160756851240767563e-19, 15, "", -15
+1.4717323521441390039399266e+05, 4, "1471732352", 6
+2.9338003399460665931997028e+00, 15, "2933800339946067", 1
+4.8882409864959196842413692e-14, 8, "", -8
+7.7474024189719434829726197e+00, 18, "7747402418971943483", 1
+2.7394167583550237210196954e-24, 0, "", 0
+3.5491065734487854284800000e+20, 15, "354910657344878542848", 21
+3.2273005278925408985433751e-24, 0, "", 0
+2.2748201134157911670782309e-23, 9, "", -9
+1.1187230024700825820168099e-19, 7, "", -7
+2.6464701651782462400730456e-03, 9, "264647", -2
+3.5549134182392484375000000e+13, 2, "3554913418239248", 14
+7.1869766956845566596712160e+00, 5, "718698", 1
+1.0457889076600547879934311e+07, 1, "104578891", 8
+3.0958654498165975000000000e+15, 17, "30958654498165975", 16
+4.2482082145085106258952656e-03, 16, "42482082145085", -2
+2.8182394704751627468800000e+20, 7, "281823947047516274688", 21
+5.4567495002765526805887930e+03, 13, "54567495002765527", 4
+4.7101557647059033584469034e+00, 14, "47101557647059", 1
+7.2728072939563989825741205e-15, 2, "", -2
+5.8801389749660546875000000e+13, 7, "58801389749660546875", 14
+6.5434519988339303540238342e-08, 10, "654", -7
+1.1654999231858433625849595e-14, 14, "1", -13
+1.0305446899115753961769912e-18, 10, "", -10
+2.4399192471098435364656742e-17, 1, "", -1
+5.1666471813051129856000000e+19, 10, "51666471813051129856", 20
+5.1857907386066163808941666e-22, 8, "", -8
+6.6290770971275501251220703e+09, 14, "662907709712755012512207", 10
+2.5609660479275934632939840e-05, 1, "", -1
+3.4764707250538327888616579e-15, 12, "", -12
+3.6204142199881157226562500e+12, 17, "362041421998811572265625", 13
+4.7365898389561859375000000e+13, 3, "47365898389561859", 14
+2.7125037836954752000000000e+18, 15, "27125037836954752", 19
+4.0715218235387645661830902e+07, 12, "40715218235387645662", 8
+1.7896673646689995257385293e-18, 4, "", -4
+4.1292688804550480563193560e+05, 12, "412926888045504806", 6
+4.7268772538939495849609375e+11, 15, "47268772538939495849609375", 12
+1.0136288370225407370031981e-10, 13, "1014", -9
+1.3454480118600272553875868e-21, 11, "", -11
+5.1492383031008296394071032e-07, 0, "", 0
+2.1869120606993481652283886e-12, 17, "218691", -11
+1.4982234624039090023495113e-02, 2, "1", -1
+2.3091277642309661865234375e+10, 15, "23091277642309661865234375", 11
+3.2204003438956257280000000e+19, 12, "3220400343895625728", 20
+7.0445823002634375000000000e+12, 6, "70445823002634375", 13
+1.2008040763842884916812181e+06, 17, "120080407638428849168122", 7
+3.3766410502443477731332539e-18, 1, "", -1
+3.6535187096868762647438427e-25, 14, "", -14
+8.3614291401061514203491714e-13, 11, "", -11
+5.0413424658121818112000000e+20, 10, "50413424658121818112", 21
+1.6403712425855234375000000e+14, 14, "16403712425855234375", 15
+3.7035573652199532261874992e+03, 10, "370355736522", 4
+3.4444785167628771972656250e+11, 5, "34444785167628772", 12
+4.0001616779831927269697189e+06, 10, "40001616779831927", 7
+2.8191886058159255981445312e+09, 5, "281918860581593", 10
+2.2490241319744193773691711e-20, 3, "", -3
+1.1029971985293119432877362e-18, 5, "", -5
+2.5932241623977885000000000e+15, 2, "25932241623977885", 16
+9.8210069797071468082186788e-11, 12, "98", -10
+6.8523899167447853088378906e+10, 3, "68523899167448", 11
+3.4833078224026580755889881e+03, 4, "34833078", 4
+1.5734344522524808593750000e+13, 17, "1573434452252480859375", 14
+3.8323737787152717393368562e-01, 8, "38323738", 0
+5.3033735681927307128906250e+10, 11, "5303373568192730712891", 11
+8.7205422658864894386310240e-03, 11, "872054227", -2
+4.2216856639087631209925067e-04, 16, "4221685663909", -3
+1.7662866167148281856000000e+20, 12, "17662866167148281856", 21
+4.2449464885037991285656679e-18, 14, "", -14
+6.8538443488680549721715766e-15, 18, "6854", -14
+1.1389686360622924610197515e+02, 17, "1138968636062292461", 3
+1.7483623880465403510661579e-22, 9, "", -9
+9.4159344393932246930489782e+02, 10, "9415934439393", 3
+2.5134290975200053978736228e-05, 0, "", 0
+3.1001816322408470169482025e-12, 6, "", -6
+8.6894933558228300800000000e+17, 10, "868949335582283008", 18
+1.7492413494784801453528409e-19, 12, "", -12
+2.1358826288442295751516360e-07, 14, "21358826", -6
+1.8960878043872732201348953e-20, 20, "2", -19
+5.6739007826950241947239206e-03, 20, "567390078269502419", -2
+7.8799484994733310298086565e-25, 17, "", -17
+1.0424287262168321910316138e-01, 16, "1042428726216832", 0
+1.8378417988923802040517330e+06, 12, "1837841798892380204", 7
+1.6321783798851461408001183e-17, 1, "", -1
+5.1816255484930211305618286e+08, 0, "518162555", 9
+8.8114761321990729514569869e-19, 5, "", -5
+1.3534580666738778020885547e+00, 8, "135345807", 1
+1.8688278068068344593048096e+09, 3, "1868827806807", 10
+1.4970096431896634987516709e-18, 20, "15", -17
+2.7561365037595989529583141e-06, 1, "", -1
+8.8597437276339700611858938e-20, 7, "", -7
+1.9450542411517362539908986e-17, 12, "", -12
+8.0410681583273947878940310e-10, 15, "804107", -9
+1.7001505802483025000000000e+15, 20, "17001505802483025", 16
+1.3848834414228553338355177e-02, 15, "13848834414229", -1
+9.8043308139340728521347046e+07, 0, "98043308", 8
+1.0885376298682442575227469e+05, 2, "10885376", 6
+3.5822690369937854497814595e-13, 9, "", -9
+3.6793146456481655934100962e-09, 13, "36793", -8
+3.2962677662953288049152434e-01, 16, "3296267766295329", 0
+1.4393296773850427500000000e+15, 8, "143932967738504275", 16
+1.0877386439574270000000000e+15, 17, "1087738643957427", 16
+4.4869023373854445002243363e-20, 15, "", -15
+4.8539220896200668750000000e+14, 16, "4853922089620066875", 15
+1.4686227229050292968750000e+10, 3, "1468622722905", 11
+9.8008350909250880000000000e+15, 3, "9800835090925088", 16
+2.0926715160486664956124458e-12, 10, "", -10
+9.5001935915099990367889404e+08, 16, "950019359150999903678894", 9
+3.4947107445084969719042064e-23, 8, "", -8
+8.2504501209905766882002354e+05, 16, "82504501209905766882", 6
+1.4047042904241477501159352e+01, 16, "140470429042414775", 2
+1.8349612076560081250000000e+14, 16, "1834961207656008125", 15
+6.9937578160056000000000000e+17, 12, "69937578160056", 18
+5.1852901126232713371888572e-03, 12, "5185290113", -2
+3.7278370837297530697440617e-04, 3, "", -3
+8.7513256367916198996681487e+01, 6, "87513256", 2
+1.4293551861526340436385485e-04, 10, "1429355", -3
+1.5172522676527982184779830e+04, 5, "1517252268", 5
+4.7249028476047632598454939e-10, 2, "", -2
+1.2093781086040714112250782e-02, 6, "12094", -1
+2.1888574464815261308103800e+04, 6, "21888574465", 5
+6.4108247849902505439759537e-14, 11, "", -11
+6.1126718192864075263059931e+01, 12, "61126718192864", 2
+4.1713893609774554960267778e+00, 8, "417138936", 1
+5.1040422024326233729427395e-10, 1, "", -1
+2.5005219675540663715272976e-19, 20, "25", -18
+1.1536360883960134968151401e-02, 4, "115", -1
+8.5370188857210814952850342e+08, 16, "8537018885721081495285034", 9
+1.3671879106543010937500000e+14, 4, "1367187910654301094", 15
+4.8758073972733228629294899e+02, 2, "48758", 3
+4.7457153105472720477052417e-05, 16, "474571531055", -4
+9.6881042339286434997985831e-04, 8, "96881", -3
+8.1300930837243213716690640e-17, 6, "", -6
+3.4505742591270232200622559e+08, 6, "345057425912702", 9
+4.7445042065697271507906047e-13, 8, "", -8
+1.8762731656955754927507130e-02, 9, "18762732", -1
+1.0998061336694069362253511e-15, 15, "1", -14
+7.7035440660781198534502348e-24, 9, "", -9
+4.1673486594549575556811760e+02, 7, "4167348659", 3
+1.6044954202024231641928775e-16, 12, "", -12
+5.1494873731001011406895637e-22, 15, "", -15
+8.1887273265700465046961440e-19, 7, "", -7
+2.4976604692390242234978359e+02, 16, "2497660469239024223", 3
+6.6620648959411733138982853e-16, 17, "67", -15
+3.5810304435982015467034383e-24, 19, "", -19
+1.2628466335209436355487000e-04, 13, "1262846634", -3
+6.9091594708094034027467956e-03, 14, "690915947081", -2
+8.8986844273515766718664564e-13, 14, "89", -12
+4.6763792380275818934409672e-24, 3, "", -3
+1.3130206257524946045067142e-21, 20, "", -20
+8.8507772162968835449218750e+11, 6, "885077721629688354", 12
+1.5745185366897158767975854e-06, 7, "16", -5
+9.8952378453471148823570951e-14, 17, "9895", -13
+5.2502470470783702218383127e-16, 10, "", -10
+8.4042755736084362792968750e+11, 7, "8404275573608436279", 12
+1.4768687205760766758203879e-09, 3, "", -3
+3.3276536174725720659828276e-03, 6, "3328", -2
+1.7589050934504477893453460e-11, 10, "", -10
+4.1339767288338470458984375e+08, 10, "4133976728833847046", 9
+5.9823531422649844913053130e-02, 13, "598235314226", -1
+5.5171659525707023620605469e+10, 12, "55171659525707023620605", 11
+1.9776168230884040527343750e+12, 0, "1977616823088", 13
+1.0990423248036367655176598e-14, 8, "", -8
+4.1467382549651870249363128e+02, 20, "41467382549651870249363", 3
+1.3508081183146977863112664e-09, 0, "", 0
+4.5294641562329785263634266e-06, 18, "4529464156233", -5
+2.2559119800193832257306280e-25, 10, "", -10
+4.1834736333573849376500131e-24, 1, "", -1
+2.4667914269831240089600000e+20, 15, "246679142698312400896", 21
+3.1118609655335848350714919e-25, 12, "", -12
+1.6083517028854200616478920e+06, 1, "16083517", 7
+2.4278838034854328937589193e-18, 11, "", -11
+3.0888949024312742039910518e+03, 4, "30888949", 4
+2.7885172028766710311174393e+07, 11, "2788517202876671031", 8
+2.4004235224723505237598431e-01, 5, "24004", 0
+2.7729909318065744638442993e+08, 5, "27729909318066", 9
+1.0612026351338697816029111e-03, 2, "", -2
+3.9610015398094952106475830e+08, 1, "396100154", 9
+2.4239501004941855297558637e-12, 20, "24239501", -11
+2.3720604005336354311449687e-14, 4, "", -4
+1.4883291451819890844482375e-04, 6, "149", -3
+3.2115853937263472062113578e+02, 2, "32116", 3
+3.1871067303438463363198737e-23, 7, "", -7
+1.4178210153362953662872314e+09, 19, "14178210153362953662872314453", 10
+1.3533633535823966553834907e+02, 14, "13533633535823967", 3
+4.6250696638119732961058617e+05, 2, "46250697", 6
+4.3666471884947684884537011e+04, 10, "436664718849477", 5
+2.1056183379767147090397713e-14, 1, "", -1
+7.9228390989314257240039296e+03, 10, "79228390989314", 4
+9.4110535356864525706082562e-20, 8, "", -8
+1.4712866191741521835327148e+10, 1, "147128661917", 11
+1.1847133517513772235659788e-20, 9, "", -9
+4.0026784400423979229965780e-10, 2, "", -2
+6.3148063574041334504727274e+03, 1, "63148", 4
+1.6962448457788511264517187e-21, 12, "", -12
+2.3900693894325259602074828e-06, 17, "239006938943", -5
+1.3860762824902351850357607e-24, 13, "", -13
+9.8520660425305834627122423e-18, 13, "", -13
+2.2869247580852769315242767e+06, 16, "22869247580852769315243", 7
+6.3803537780441718041402055e+02, 1, "638", 3
+1.8412544531117088000000000e+17, 3, "18412544531117088", 18
+1.7776908766615158583590528e+03, 18, "1777690876661515858359", 4
+5.4351023950463787500000000e+14, 14, "543510239504637875", 15
+6.8658881818589908172800000e+20, 13, "686588818185899081728", 21
+2.9494585632809057235717773e+09, 0, "2949458563", 10
+3.6545577159534293370298647e-07, 20, "36545577159534", -6
+6.5526675467397988541051745e+04, 18, "65526675467397988541052", 5
+1.7242830649181970799231419e-10, 7, "", -7
+6.5639944669509546315566695e+01, 19, "656399446695095463156", 2
+1.3156608464108407452464178e-01, 16, "1315660846410841", 0
+1.2963919749964332368108444e+04, 3, "1296392", 5
+7.4894923110693805866008854e-05, 16, "748949231107", -4
+1.0888074151891450887856709e-15, 6, "", -6
+1.2301403127947672544451052e+01, 6, "12301403", 2
+3.8945245867053290567127988e+03, 12, "3894524586705329", 4
+7.8750805495133032285337724e-21, 5, "", -5
+2.0258224546475161488785752e-08, 2, "", -2
+1.7581992138894326880816173e-24, 18, "", -18
+1.2218910953381130099296570e+08, 12, "122189109533811300993", 9
+4.2411828323146371891069867e-23, 13, "", -13
+4.1188705410900964678789291e-14, 8, "", -8
+3.5041538991843825812111390e+00, 15, "3504153899184383", 1
+6.9939825339778212890625000e+12, 17, "69939825339778212890625", 13
+1.2604357096145542883580049e-14, 4, "", -4
+1.3618112230571125000000000e+14, 16, "13618112230571125", 15
+1.5426824998575691965421426e-06, 8, "154", -5
+6.4802012644741805532224698e-25, 19, "", -19
+6.5434939826304223388433456e+06, 17, "654349398263042233884335", 7
+2.8593196098489642333984375e+11, 12, "285931960984896423339844", 12
+3.6395924367265995000000000e+15, 1, "36395924367265995", 16
+9.9450235071871048204853252e-06, 2, "", -2
+1.8028582003601691759135957e-13, 8, "", -8
+6.8491170370267743020766969e-08, 6, "", -6
+2.8418488268429373340382029e-08, 1, "", -1
+1.6058523696864046505401735e-04, 15, "160585236969", -3
+2.0204048673917219275608659e+04, 11, "2020404867391722", 5
+1.0641148619533082500000000e+15, 4, "106411486195330825", 16
+1.1490012212951497113600000e+20, 15, "114900122129514971136", 21
+3.9303075613940547053539542e-23, 15, "", -15
+2.3365797618258078049339357e-13, 5, "", -5
+6.8055753141123428344726562e+10, 18, "680557531411234283447265625", 11
+2.9466628744340115000000000e+15, 17, "29466628744340115", 16
+1.1171292917846032418882333e-13, 1, "", -1
+6.8856058519301601705819849e+00, 8, "688560585", 1
+2.9919256687993507385253906e+10, 19, "2991925668799350738525390625", 11
+4.2384542059898598400000000e+17, 1, "423845420598985984", 18
+1.5277977544427925226310991e-05, 3, "", -3
+4.4452305734866932034492493e+07, 4, "444523057349", 8
+6.5546531491364749312000000e+19, 0, "65546531491364749312", 20
+1.9842672424587858159370710e-12, 4, "", -4
+2.9075601794879745646930924e-05, 4, "", -4
+2.2410325424521251989062876e+03, 7, "22410325425", 4
+1.5876167931261899414062500e+12, 12, "158761679312618994140625", 13
+7.2915824924726416015625000e+11, 5, "72915824924726416", 12
+6.0490382570772591347778295e-11, 13, "605", -10
+3.8944305553351275936645242e-17, 13, "", -13
+2.9148237575325779857848829e+01, 13, "291482375753258", 2
+2.0210978880658891282527658e-23, 0, "", 0
+7.3526308801384485695974545e-20, 12, "", -12
+1.3658656241786268718437013e-11, 15, "13659", -10
+1.8126222156524613174813396e-12, 19, "18126222", -11
+5.6254876168808987131342292e+03, 0, "5625", 4
+6.6882034415542034432000000e+19, 18, "66882034415542034432", 20
+6.8210058358683609600000000e+17, 13, "682100583586836096", 18
+1.0239489841935416105118316e-25, 10, "", -10
+6.4885530802579514682292938e+07, 14, "6488553080257951468229", 8
+4.6831130092816418889796811e-11, 15, "46831", -10
+2.7411837319155561600000000e+17, 18, "274118373191555616", 18
+9.6050524824558010368000000e+19, 19, "96050524824558010368", 20
+9.2768174103640237500000000e+14, 15, "927681741036402375", 15
+2.6781929928089680671691895e+09, 15, "2678192992808968067169189", 10
+1.1046304602372358205620261e-05, 11, "110463", -4
+1.0841960471643238830566406e+11, 5, "10841960471643239", 12
+2.6298793785197580963018625e-11, 12, "26", -10
+3.5106538053044732805574313e+03, 9, "3510653805304", 4
+4.2735983858635887596764252e-11, 13, "427", -10
+5.3007529384454594560000000e+19, 11, "5300752938445459456", 20
+3.6627230212689530849456787e+08, 6, "366272302126895", 9
+6.3444042930495486633002715e-07, 8, "63", -6
+3.5100531800601215062677986e-14, 8, "", -8
+1.7286776468325945610438055e-01, 1, "2", 0
+2.9467144324665499648000000e+19, 12, "29467144324665499648", 20
+2.4075011043657265368295950e-14, 2, "", -2
+2.5022998586714197196800000e+20, 15, "250229985867141971968", 21
+4.4003794398566061916691624e-17, 7, "", -7
+2.3423233464175251632517880e-24, 15, "", -15
+2.4521081548063623500866015e+00, 11, "245210815481", 1
+1.6722093550107796744441657e+01, 20, "1672209355010779674444", 2
+1.5383165351761283522953959e-09, 15, "1538317", -8
+7.0092804024077781250000000e+13, 15, "7009280402407778125", 14
+1.3322274046342386100150179e+00, 11, "133222740463", 1
+1.9025988459395125665880699e-10, 11, "19", -9
+2.7309308556335416320000000e+18, 4, "2730930855633541632", 19
+4.9530533186694964027652066e-04, 14, "49530533187", -3
+3.4480953504032777345855720e+03, 4, "34480954", 4
+7.3181776721744760627022704e-06, 17, "731817767217", -5
+7.3559657425321643212800000e+20, 14, "735596574253216432128", 21
+1.2412295595365066056111728e-14, 4, "", -4
+8.7697253663625735961494544e-08, 16, "876972537", -7
+2.2699582135102709667950904e-02, 1, "", -1
+4.2529222202524316346631772e-10, 13, "4253", -9
+5.9819377324581878951903491e+01, 9, "59819377325", 2
+4.4109863875065528320000000e+19, 8, "4410986387506552832", 20
+4.4731766697893267822265625e+11, 2, "44731766697893", 12
+1.5401217392608513869803196e-13, 20, "15401217", -12
+1.7951936368179281250000000e+13, 9, "1795193636817928125", 14
+2.1829691697830064000000000e+17, 12, "21829691697830064", 18
+1.5909596501424949676532114e-14, 18, "1591", -13
+5.4099197193774011086321337e-25, 2, "", -2
+6.9242442431238749118500644e-21, 18, "", -18
+9.2196686858616040000000000e+15, 5, "9219668685861604", 16
+3.7675814609568682857403604e-09, 13, "37676", -8
+7.1034765852635580813512206e+04, 13, "710347658526355808", 5
+2.1403397077492739009052514e-01, 15, "214033970774927", 0
+2.7701031177007259391790669e-06, 15, "2770103118", -5
+2.9478547696164588559630815e-02, 11, "294785477", -1
+9.8829877680244670464000000e+19, 4, "98829877680244670464", 20
+6.5059737427122506956800000e+20, 1, "650597374271225069568", 21
+1.2368063411364548863820201e-10, 6, "", -6
+3.4869431419309659184536037e-08, 10, "349", -7
+2.4936581684364624000000000e+17, 10, "24936581684364624", 18
+9.8114476206485559509966970e-20, 10, "", -10
+4.1025023707394424916405049e-19, 14, "", -14
+1.7634002265096694463863969e+05, 12, "176340022650966945", 6
+7.6497765877147115520000000e+18, 5, "7649776587714711552", 19
+1.3087152273935693063008895e-19, 6, "", -6
+1.8195267016330175702595965e-19, 8, "", -8
+7.9374857953483275356889887e-07, 11, "79375", -6
+1.9383514842742362585193781e-10, 16, "1938351", -9
+7.0779474772986286506016959e-22, 6, "", -6
+1.1495473374695556238293648e+07, 11, "1149547337469555624", 8
+5.5055657308194036333803085e-08, 5, "", -5
+2.7852820511326191406250000e+12, 20, "2785282051132619140625", 13
+9.5823552717485662500000000e+14, 19, "958235527174856625", 15
+5.7615109537071903545701163e-24, 10, "", -10
+4.7342526369214909644800000e+20, 3, "473425263692149096448", 21
+1.2562254158337033658979271e-08, 19, "125622541583", -7
+1.4802542139968126733151621e+00, 11, "1480254214", 1
+5.0638737484134515625000000e+13, 10, "50638737484134515625", 14
+1.3592777121960071251832017e-21, 7, "", -7
+8.8390426511071667004882722e-10, 7, "", -7
+1.4043213577062855861553314e-05, 1, "", -1
+1.2151254397241963774601442e-04, 19, "1215125439724196", -3
+3.5315572342564691603143939e-06, 4, "", -4
+2.3326678644170604115699874e-05, 9, "23327", -4
+1.0861797296891001356171849e-16, 0, "", 0
+1.8710943560782242566347122e+07, 9, "18710943560782243", 8
+1.6244984276745969238281250e+12, 18, "1624498427674596923828125", 13
+3.9417413418522492051124573e+07, 12, "39417413418522492051", 8
+1.1445411083918325424194336e+10, 5, "1144541108391833", 11
+5.7237525903208702802658081e+06, 16, "57237525903208702802658", 7
+2.9784940910460998460262960e-03, 9, "2978494", -2
+1.6914379697127038996664781e-07, 5, "", -5
+5.4455612727104390400000000e+17, 8, "544556127271043904", 18
+5.2019886390219737600000000e+17, 2, "520198863902197376", 18
+8.2863646359445989131927490e+08, 0, "828636464", 9
+2.0558064885994301162558782e-24, 11, "", -11
+3.4992116082573336832695077e+00, 9, "3499211608", 1
+4.0203247113518275320529938e+07, 20, "4020324711351827532052993774", 8
+4.5270794923097397986934800e-07, 19, "452707949231", -6
+1.7176252873964098010865281e-25, 12, "", -12
+5.0261906139138740539550781e+10, 18, "5026190613913874053955078125", 11
+7.1481562517751414322309650e-11, 14, "7148", -10
+8.7281765927491912841796875e+10, 1, "872817659275", 11
+1.9541466886643892224000000e+20, 6, "19541466886643892224", 21
+2.4610302704998766421340406e+05, 14, "24610302704998766421", 6
+5.5123777635746188056536473e-18, 8, "", -8
+2.4928214717947334051132202e+07, 3, "24928214718", 8
+3.3226582281614020466804504e+07, 13, "332265822816140204668", 8
+6.2072012586622351463245565e-21, 11, "", -11
+4.5056698751514278942892183e-15, 19, "45057", -14
+4.3970925100077403340800000e+20, 5, "439709251000774033408", 21
+3.0851338961425274976127514e-24, 12, "", -12
+5.8359358944206739646107865e-13, 1, "", -1
+3.1787063701593344637432248e-10, 7, "", -7
+2.5909266012162019822201313e-14, 12, "", -12
+6.6087793641703175380825996e+06, 15, "6608779364170317538083", 7
+2.7606710141689967934468009e-09, 5, "", -5
+9.4241244366368280000000000e+15, 0, "9424124436636828", 16
+1.6946301135649606860800000e+20, 14, "169463011356496068608", 21
+1.1633778535846001409866942e-10, 10, "1", -9
+8.7370588406131942350402951e-16, 17, "87", -15
+2.5261077139618090188800000e+20, 19, "252610771396180901888", 21
+6.4204835963286673968983785e-06, 20, "642048359632867", -5
+5.1132165601358985107006971e-05, 11, "5113217", -4
+1.6661669314435270794989134e-15, 4, "", -4
+3.0939146368062910898657803e-08, 4, "", -4
+1.1788804193679672753904478e-06, 5, "", -5
+2.2258206753076657346927802e-05, 6, "22", -4
+3.1689207094414674400427438e-21, 18, "", -18
+1.2077597747447968487843905e-07, 6, "", -6
+8.7305702781782993738073102e-17, 20, "8731", -16
+8.5839582307966081806789369e-23, 19, "", -19
+6.4195037716659086868276063e+01, 13, "641950377166591", 2
+6.8094721563524294827354005e-14, 20, "6809472", -13
+1.3497058415056765170447761e+03, 2, "134971", 4
+6.2157220865387843585982682e-22, 6, "", -6
+4.0667476120535902964821945e-05, 7, "407", -4
+2.7443459063225157024135115e+02, 11, "27443459063225", 3
+1.0210280291049479764198286e-21, 15, "", -15
+8.4623169154827225065833998e-15, 5, "", -5
+9.0379104578354190414953347e-24, 1, "", -1
+1.0178039752907980978488922e+08, 17, "10178039752907980978488922", 9
+3.9328276391966760412659848e-13, 18, "393283", -12
+1.5693085798287499852185124e-21, 11, "", -11
+1.7549893820738936126880925e-04, 18, "175498938207389", -3
+3.2969031476469676971435547e+10, 16, "329690314764696769714355469", 11
+1.1074978118120412017911161e-09, 4, "", -4
+1.4949843615328078253844051e-08, 9, "15", -7
+2.5320604848073559570312500e+11, 20, "253206048480735595703125", 12
+5.0088305271920396943841070e-01, 16, "500883052719204", 0
+1.1672709000476220703125000e+13, 18, "11672709000476220703125", 14
+7.9270804309913904333091523e-18, 16, "", -16
+1.4656956192078695450874619e-17, 2, "", -2
+5.9176968707453587725808575e+00, 20, "591769687074535877258", 1
+2.6632456385956746455858530e-21, 20, "", -20
+8.8910205055289922779215850e-04, 4, "9", -3
+1.1383168644297999572753906e+11, 16, "1138316864429799957275390625", 12
+1.5873838069057359945190910e+00, 18, "1587383806905735995", 1
+6.2048690998854036580907166e-19, 20, "62", -18
+6.0243428916704624976496931e-13, 0, "", 0
+1.4113606110846559360538777e+01, 6, "14113606", 2
+2.2980332330713289613057389e-16, 16, "2", -15
+6.4407712171390029296875000e+12, 13, "64407712171390029296875", 13
+2.3314190694870136212557554e+05, 19, "2331419069487013621255755", 6
+1.3430408310358017187500000e+14, 6, "134304083103580171875", 15
+1.7523999633198167430236936e+05, 14, "1752399963319816743", 6
+1.2779523625280151367187500e+12, 12, "127795236252801513671875", 13
+4.9237880877891928292403883e-18, 0, "", 0
+5.6987021703943800000000000e+15, 17, "569870217039438", 16
+6.9443875068581306209125614e+01, 7, "694438751", 2
+1.1437059899241757392883301e+09, 14, "114370598992417573928833", 10
+4.3847185549378956539562516e-13, 8, "", -8
+1.4938268218607690869248472e+03, 8, "149382682186", 4
+2.9051342859610294346845748e-09, 12, "2905", -8
+8.8992459877740567684331863e-18, 11, "", -11
+2.8182953222292413814065171e-02, 18, "28182953222292414", -1
+2.6941036307872906250000000e+14, 7, "2694103630787290625", 15
+1.2786627566899886718750000e+13, 15, "1278662756689988671875", 14
+7.4760548248557870465447195e+02, 7, "7476054825", 3
+2.0808903278641173005744941e-19, 3, "", -3
+1.3675577564048088088834859e-06, 10, "13676", -5
+9.0314818930726431744915317e+01, 12, "90314818930726", 2
+1.2637940381002242187500000e+13, 1, "126379403810022", 14
+6.2898404226945890964108274e-13, 15, "629", -12
+2.7096055920233681036126094e-18, 12, "", -12
+2.2400915495900110213271687e-24, 12, "", -12
+1.1916670164356988281250000e+13, 3, "11916670164356988", 14
+2.3625749985895959472656250e+11, 10, "2362574998589595947266", 12
+6.4096945917386077344417572e+07, 10, "640969459173860773", 8
+1.0288156592379195988178253e+08, 3, "102881565924", 9
+2.4914143675061010269056183e-05, 14, "2491414368", -4
+2.1806993712021089843750000e+13, 12, "2180699371202108984375", 14
+6.4497571429801403286115174e-25, 14, "", -14
+4.2397460719371648000000000e+17, 4, "42397460719371648", 18
+7.3671485757890977353052685e-09, 1, "", -1
+5.2590283508103025989893197e-17, 7, "", -7
+1.5295266445534963159480490e-02, 0, "", 0
+8.0980423292442119418410584e+03, 7, "80980423292", 4
+1.3496362955090356550158504e+01, 17, "1349636295509035655", 2
+1.6789689243310512392781675e+05, 0, "167897", 6
+3.6914158304578734259848716e+01, 8, "369141583", 2
+3.0187540777596878765507249e-20, 13, "", -13
+2.7638631280263869716716355e-12, 9, "", -9
+1.4497982429677158594131470e+07, 4, "144979824297", 8
+1.5036175336625990625000000e+14, 17, "15036175336625990625", 15
+1.3242598863494831085205078e+10, 12, "13242598863494831085205", 11
+2.5695863591886435983724368e+01, 10, "256958635919", 2
+7.9115417097347208165659297e-20, 16, "", -16
+2.1149997306580013312308082e-20, 20, "2", -19
+3.3026673447749831016156952e-04, 1, "", -1
+5.3503303421835358226421384e-17, 9, "", -9
+3.8831254347078791835265926e-18, 9, "", -9
+4.7567957893639957673345003e-05, 8, "4757", -4
+8.1707666473813178017735481e+06, 19, "81707666473813178017735481", 7
+1.6683344748855767039044893e-17, 5, "", -5
+4.5021961994715490341186523e+09, 11, "450219619947154903412", 10
+1.6107496358885451660156250e+12, 8, "161074963588854516602", 13
+5.8385589949200648000000000e+16, 15, "58385589949200648", 17
+7.8318206826911029860838198e-01, 6, "783182", 0
+4.9622049137181640922491605e-14, 0, "", 0
+1.4378956657306312000000000e+16, 14, "14378956657306312", 17
+1.8049411292578543264397695e+00, 11, "180494112926", 1
+9.4612947207965114368000000e+20, 2, "94612947207965114368", 21
+1.4370027736554941810709352e+01, 15, "14370027736554942", 2
+9.0053138015373294051477073e-09, 20, "900531380154", -8
+1.8129318212242679295759077e-13, 12, "", -12
+3.6556116517026299904000000e+20, 17, "36556116517026299904", 21
+3.6644643458493050880000000e+19, 5, "3664464345849305088", 20
+2.8152889402261430518007498e-06, 14, "281528894", -5
+8.3283083892446570098400116e+05, 20, "83283083892446570098400116", 6
+2.2661217256252738560000000e+18, 18, "2266121725625273856", 19
+4.2917205376219216164986152e-12, 8, "", -8
+5.5092300080573593139648438e+10, 3, "55092300080574", 11
+2.6595744001830953298028204e-20, 12, "", -12
+1.3250886292356894552211232e-25, 8, "", -8
+4.1380622625061248779296875e+10, 5, "4138062262506125", 11
+1.9398605768909324979176745e+04, 5, "1939860577", 5
+1.7443014783548167591016528e-13, 5, "", -5
+4.0314889972364077917213075e-15, 9, "", -9
+4.8877837161900931613536803e-05, 10, "488778", -4
+1.4638030286503930000000000e+16, 5, "1463803028650393", 17
+1.1524420738001751873813561e-01, 5, "11524", 0
+8.4652385404623579233884811e+04, 13, "846523854046235792", 5
+6.0220579812021087855100632e+06, 4, "60220579812", 7
+1.0701946041039131250000000e+15, 2, "107019460410391313", 16
+4.7823816788611670405904570e-11, 10, "", -10
+7.4530166572716260390413234e-04, 14, "74530166573", -3
+5.6520202124764686857361085e+01, 5, "565202", 2
+3.7948207646837112119766874e-15, 17, "379", -14
+3.5202783002279891560317444e-14, 13, "", -13
+7.2773137506371057270371239e+01, 10, "727731375064", 2
+5.5947230123447582172957482e+01, 15, "55947230123447582", 2
+5.8730508358888007700443268e+07, 1, "587305084", 8
+9.2930694929375841362162447e-03, 11, "929306949", -2
+7.1398558534035156952768375e+00, 4, "71399", 1
+3.1512476363439206232877621e-05, 13, "315124764", -4
+7.1427226984130737989634267e-09, 15, "7142723", -8
+4.0496915700094192671592753e-25, 2, "", -2
+1.1366821577444322348476012e-21, 3, "", -3
+7.0692445057512618653489962e-21, 18, "", -18
+1.8771838307312936782836914e+09, 5, "187718383073129", 10
+1.4624501735454128609865783e-25, 8, "", -8
+9.7592076026378738233135265e-23, 11, "", -11
+3.5540383417775919951964170e+04, 7, "355403834178", 5
+2.6071255376172006130218506e+08, 20, "26071255376172006130218505859", 9
+2.7556489960406188000000000e+16, 2, "27556489960406188", 17
+2.3270608663029260857015360e-07, 13, "2327061", -6
+1.9809674824468212688532761e-22, 3, "", -3
+2.1691642655829796240141150e+03, 11, "216916426558298", 4
+2.1695953449070249023437500e+12, 6, "2169595344907024902", 13
+1.1089352899635693434909900e-03, 4, "11", -2
+6.0979904920805606816092137e-02, 12, "60979904921", -1
+7.6813002386500807479023933e+06, 19, "76813002386500807479023933", 7
+1.3562346900285739049709059e-18, 20, "136", -17
+1.7435274851516845537491001e-15, 8, "", -8
+2.4579859491280314448975162e-14, 6, "", -6
+7.2683778342362960565165020e-04, 13, "7268377834", -3
+4.8569612326585259288549423e+06, 20, "485696123265852592885494232", 7
+3.5358855158619100057618940e-21, 11, "", -11
+1.0503082522542129135369380e-18, 11, "", -11
+3.6273148704706104103288924e-20, 0, "", 0
+1.1071824053947776250000000e+15, 20, "1107182405394777625", 16
+6.6010138378270921677426486e-01, 13, "6601013837827", 0
+5.4231781740024906484458752e-20, 0, "", 0
+2.45222521962435200000