RyuDouble.java

  1. /* Copyright 2018 Ulf Adams
  2.  * Licensed to the Hipparchus project under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The Hipparchus project licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      https://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */

  17. /*
  18.  * This is not the original file distributed by Ulf Adams in project
  19.  * https://github.com/ulfjack/ryu
  20.  * It has been modified by the Hipparchus project.
  21.  */
  22. package org.hipparchus.util;

  23. import java.math.BigInteger;

  24. import org.hipparchus.exception.LocalizedCoreFormats;
  25. import org.hipparchus.exception.MathIllegalArgumentException;

  26. /**
  27.  * An implementation of Ryū for double.
  28.  * <p>
  29.  * Ryū generates the shortest decimal representation of a floating point number
  30.  * that maintains round-trip safety. That is, a correct parser can recover the
  31.  * exact original number. Ryū is very fast (about 10 time faster than {@code
  32.  * Double.toString()}).
  33.  * </p>
  34.  * @see <a href="https://dl.acm.org/citation.cfm?doid=3296979.3192369">Ryū: fast float-to-string conversion</a>
  35.  */
  36. public final class RyuDouble {

  37.     /** Default low switch level to scientific notation. */
  38.     public static final int DEFAULT_LOW_EXP = -3;

  39.     /** Default high switch level to scientific notation. */
  40.     public static final int DEFAULT_HIGH_EXP = 7;

  41.     /** Number of bits in a double mantissa. */
  42.     private static final int DOUBLE_MANTISSA_BITS = 52;

  43.     /** Bit mask for retrieving mantissa. */
  44.     private static final long DOUBLE_MANTISSA_MASK = (1L << DOUBLE_MANTISSA_BITS) - 1;

  45.     /** Number of bits in a double exponant. */
  46.     private static final int DOUBLE_EXPONENT_BITS = 11;

  47.     /** Bit mask for retrieving exponent. */
  48.     private static final int DOUBLE_EXPONENT_MASK = (1 << DOUBLE_EXPONENT_BITS) - 1;

  49.     /** Bias of the exponent. */
  50.     private static final int DOUBLE_EXPONENT_BIAS = (1 << (DOUBLE_EXPONENT_BITS - 1)) - 1;

  51.     /** Size of the factors table for positive exponents. */
  52.     private static final int POS_TABLE_SIZE = 326;

  53.     /** Size of the factors table for negative exponents. */
  54.     private static final int NEG_TABLE_SIZE = 291;

  55.     /** Bit count for complete entries in the positive exponent tables. */
  56.     private static final int POW5_BITCOUNT = 121; // max 3*31 = 124

  57.     /** Bit count for split entries in the positive exponent tables. */
  58.     private static final int POW5_QUARTER_BITCOUNT = 31;

  59.     /** Split table for positive exponents. */
  60.     private static final int[][] POW5_SPLIT = new int[POS_TABLE_SIZE][4];

  61.     /** Bit count for complete entries in the negative exponent tables. */
  62.     private static final int POW5_INV_BITCOUNT = 122; // max 3*31 = 124

  63.     /** Bit count for split entries in the negative exponent tables. */
  64.     private static final int POW5_INV_QUARTER_BITCOUNT = 31;

  65.     /** Split table for negative exponents. */
  66.     private static final int[][] POW5_INV_SPLIT = new int[NEG_TABLE_SIZE][4];

  67.     /** Create the tables. */
  68.     static {
  69.         final BigInteger mask = BigInteger.valueOf(1).shiftLeft(POW5_QUARTER_BITCOUNT).subtract(BigInteger.ONE);
  70.         final BigInteger invMask = BigInteger.valueOf(1).shiftLeft(POW5_INV_QUARTER_BITCOUNT).subtract(BigInteger.ONE);
  71.         for (int i = 0; i < FastMath.max(POS_TABLE_SIZE, NEG_TABLE_SIZE); i++) {
  72.             final BigInteger pow = BigInteger.valueOf(5).pow(i);
  73.             final int pow5len = pow.bitLength();
  74.             if (i < POW5_SPLIT.length) {
  75.                 for (int j = 0; j < 4; j++) {
  76.                     POW5_SPLIT[i][j] = pow.
  77.                                        shiftRight(pow5len - POW5_BITCOUNT + (3 - j) * POW5_QUARTER_BITCOUNT).
  78.                                        and(mask).
  79.                                        intValueExact();
  80.                 }
  81.             }

  82.             if (i < POW5_INV_SPLIT.length) {
  83.                 // We want floor(log_2 5^q) here, which is pow5len - 1.
  84.                 final int j = pow5len - 1 + POW5_INV_BITCOUNT;
  85.                 final BigInteger inv = BigInteger.ONE.shiftLeft(j).divide(pow).add(BigInteger.ONE);
  86.                 for (int k = 0; k < 4; k++) {
  87.                     if (k == 0) {
  88.                         POW5_INV_SPLIT[i][k] = inv.shiftRight((3 - k) * POW5_INV_QUARTER_BITCOUNT).intValueExact();
  89.                     } else {
  90.                         POW5_INV_SPLIT[i][k] = inv.shiftRight((3 - k) * POW5_INV_QUARTER_BITCOUNT).and(invMask).intValueExact();
  91.                     }
  92.                 }
  93.             }
  94.         }
  95.     }

  96.     /** Private constructor for a utility class.
  97.      */
  98.     private RyuDouble() {
  99.         // nothing to do
  100.     }

  101.     /** Convert a double to shortest string representation, preserving full accuracy.
  102.      * <p>
  103.      * This implementation uses the same specifications as {@code Double.toString()},
  104.      * i.e. it uses scientific notation if for numbers smaller than 10⁻³ or larger
  105.      * than 10⁺⁷, and decimal notion in between. That is it call {@link #doubleToString(double,
  106.      * int, int) doubleToString(value, -3, 7)}.
  107.      * </p>
  108.      * @param value double number to convert
  109.      * @return shortest string representation
  110.      * @see #doubleToString(double, int, int)
  111.      * @see #DEFAULT_LOW_EXP
  112.      * @see #DEFAULT_HIGH_EXP
  113.      */
  114.     public static String doubleToString(double value) {
  115.         return doubleToString(value, DEFAULT_LOW_EXP, DEFAULT_HIGH_EXP);
  116.     }

  117.     /** Convert a double to shortest string representation, preserving full accuracy.
  118.      * <p>
  119.      * Number inside of the interval [10<sup>lowExp</sup>, 10<sup>highExp</sup>]
  120.      * are represented using decimal notation, numbers outside of this
  121.      * range are represented using scientific notation.
  122.      * </p>
  123.      * @param value double number to convert
  124.      * @param lowExp lowest decimal exponent for which decimal notation can be used
  125.      * @param highExp highest decimal exponent for which decimal notation can be used
  126.      * @return shortest string representation
  127.      * @see #doubleToString(double)
  128.      * @see #DEFAULT_LOW_EXP
  129.      * @see #DEFAULT_HIGH_EXP
  130.      */
  131.     public static String doubleToString(double value, int lowExp, int highExp) {
  132.         // Step 1: Decode the floating point number, and unify normalized and subnormal cases.
  133.         // First, handle all the trivial cases.
  134.         if (Double.isNaN(value)) {
  135.             return "NaN";
  136.         }
  137.         if (value == Double.POSITIVE_INFINITY) {
  138.             return "Infinity";
  139.         }
  140.         if (value == Double.NEGATIVE_INFINITY) {
  141.             return "-Infinity";
  142.         }
  143.         long bits = Double.doubleToLongBits(value);
  144.         if (bits == 0) {
  145.             return "0.0";
  146.         }
  147.         if (bits == 0x8000000000000000L) {
  148.             return "-0.0";
  149.         }

  150.         // Otherwise extract the mantissa and exponent bits and run the full algorithm.
  151.         final int ieeeExponent = (int) ((bits >>> DOUBLE_MANTISSA_BITS) & DOUBLE_EXPONENT_MASK);
  152.         final long ieeeMantissa = bits & DOUBLE_MANTISSA_MASK;
  153.         int e2;
  154.         final long m2;
  155.         if (ieeeExponent == 0) {
  156.             // Denormal number - no implicit leading 1, and the exponent is 1, not 0.
  157.             e2 = 1 - DOUBLE_EXPONENT_BIAS - DOUBLE_MANTISSA_BITS;
  158.             m2 = ieeeMantissa;
  159.         } else {
  160.             // Add implicit leading 1.
  161.             e2 = ieeeExponent - DOUBLE_EXPONENT_BIAS - DOUBLE_MANTISSA_BITS;
  162.             m2 = ieeeMantissa | (1L << DOUBLE_MANTISSA_BITS);
  163.         }

  164.         final boolean sign = bits < 0;

  165.         // Step 2: Determine the interval of legal decimal representations.
  166.         final boolean even = (m2 & 1) == 0;
  167.         final long mv = 4 * m2;
  168.         final long mp = 4 * m2 + 2;
  169.         final int mmShift = ((m2 != (1L << DOUBLE_MANTISSA_BITS)) || (ieeeExponent <= 1)) ? 1 : 0;
  170.         final long mm = 4 * m2 - 1 - mmShift;
  171.         e2 -= 2;

  172.         // Step 3: Convert to a decimal power base using 128-bit arithmetic.
  173.         // -1077 = 1 - 1023 - 53 - 2 <= e_2 - 2 <= 2046 - 1023 - 53 - 2 = 968
  174.         long dv;
  175.         long dp;
  176.         long dm;
  177.         final int e10;
  178.         boolean dmIsTrailingZeros = false;
  179.         boolean dvIsTrailingZeros = false;
  180.         if (e2 >= 0) {
  181.             final int q = FastMath.max(0, ((e2 * 78913) >>> 18) - 1);
  182.             // k = constant + floor(log_2(5^q))
  183.             final int k = POW5_INV_BITCOUNT + pow5bits(q) - 1;
  184.             final int i = -e2 + q + k;
  185.             dv = mulPow5InvDivPow2(mv, q, i);
  186.             dp = mulPow5InvDivPow2(mp, q, i);
  187.             dm = mulPow5InvDivPow2(mm, q, i);
  188.             e10 = q;

  189.             if (q <= 21) {
  190.                 if (mv % 5 == 0) {
  191.                     dvIsTrailingZeros = multipleOfPowerOf5(mv, q);
  192.                 } else if (even) {
  193.                     dmIsTrailingZeros = multipleOfPowerOf5(mm, q);
  194.                 } else if (multipleOfPowerOf5(mp, q)) {
  195.                     dp--;
  196.                 }
  197.             }
  198.         } else {
  199.             final int q = FastMath.max(0, ((-e2 * 732923) >>> 20) - 1);
  200.             final int i = -e2 - q;
  201.             final int k = pow5bits(i) - POW5_BITCOUNT;
  202.             final int j = q - k;
  203.             dv = mulPow5divPow2(mv, i, j);
  204.             dp = mulPow5divPow2(mp, i, j);
  205.             dm = mulPow5divPow2(mm, i, j);
  206.             e10 = q + e2;
  207.             if (q <= 1) {
  208.                 dvIsTrailingZeros = true;
  209.                 if (even) {
  210.                     dmIsTrailingZeros = mmShift == 1;
  211.                 } else {
  212.                     dp--;
  213.                 }
  214.             } else if (q < 63) {
  215.                 dvIsTrailingZeros = (mv & ((1L << (q - 1)) - 1)) == 0;
  216.             }
  217.         }

  218.         // Step 4: Find the shortest decimal representation in the interval of legal representations.
  219.         //
  220.         // We do some extra work here in order to follow Float/Double.toString semantics. In particular,
  221.         // that requires printing in scientific format if and only if the exponent is between lowExp and highExp,
  222.         // and it requires printing at least two decimal digits.
  223.         //
  224.         // Above, we moved the decimal dot all the way to the right, so now we need to count digits to
  225.         // figure out the correct exponent for scientific notation.
  226.         final int vplength = decimalLength(dp);
  227.         int exp = e10 + vplength - 1;

  228.         // use scientific notation if and only if outside this range.
  229.         final boolean scientificNotation = !((exp >= lowExp) && (exp < highExp));

  230.         int removed = 0;

  231.         int lastRemovedDigit = 0;
  232.         long output;
  233.         if (dmIsTrailingZeros || dvIsTrailingZeros) {
  234.             while (dp / 10 > dm / 10) {
  235.                 if ((dp < 100) && scientificNotation) {
  236.                     // Double.toString semantics requires printing at least two digits.
  237.                     break;
  238.                 }
  239.                 dmIsTrailingZeros &= dm % 10 == 0;
  240.                 dvIsTrailingZeros &= lastRemovedDigit == 0;
  241.                 lastRemovedDigit = (int) (dv % 10);
  242.                 dp /= 10;
  243.                 dv /= 10;
  244.                 dm /= 10;
  245.                 removed++;
  246.             }
  247.             if (dmIsTrailingZeros && even) {
  248.                 while (dm % 10 == 0) {
  249.                     if ((dp < 100) && scientificNotation) {
  250.                         // Double.toString semantics requires printing at least two digits.
  251.                         break;
  252.                     }
  253.                     dvIsTrailingZeros &= lastRemovedDigit == 0;
  254.                     lastRemovedDigit = (int) (dv % 10);
  255.                     dp /= 10;
  256.                     dv /= 10;
  257.                     dm /= 10;
  258.                     removed++;
  259.                 }
  260.             }
  261.             if (dvIsTrailingZeros && (lastRemovedDigit == 5) && (dv % 2 == 0)) {
  262.                 // Round even if the exact numbers is .....50..0.
  263.                 lastRemovedDigit = 4;
  264.             }
  265.             output = dv +
  266.                             ((dv == dm && !(dmIsTrailingZeros && even)) || (lastRemovedDigit >= 5) ? 1 : 0);
  267.         } else {
  268.             while (dp / 10 > dm / 10) {
  269.                 if ((dp < 100) && scientificNotation) {
  270.                     // Double.toString semantics requires printing at least two digits.
  271.                     break;
  272.                 }
  273.                 lastRemovedDigit = (int) (dv % 10);
  274.                 dp /= 10;
  275.                 dv /= 10;
  276.                 dm /= 10;
  277.                 removed++;
  278.             }
  279.             output = dv + ((dv == dm || (lastRemovedDigit >= 5)) ? 1 : 0);
  280.         }
  281.         int olength = vplength - removed;

  282.         // Step 5: Print the decimal representation.
  283.         // We follow Double.toString semantics here,
  284.         // but adjusting the boundaries at which we switch to scientific notation
  285.         char[] result = new char[14 - lowExp + highExp];
  286.         int index = 0;
  287.         if (sign) {
  288.             result[index++] = '-';
  289.         }

  290.         // Values in the interval [10^lowExp, 10^highExp) are special.
  291.         if (scientificNotation) {
  292.             // Print in the format x.xxxxxE-yy.
  293.             for (int i = 0; i < olength - 1; i++) {
  294.                 int c = (int) (output % 10);
  295.                 output /= 10;
  296.                 result[index + olength - i] = (char) ('0' + c);
  297.             }
  298.             result[index] = (char) ('0' + output % 10);
  299.             result[index + 1] = '.';
  300.             index += olength + 1;
  301.             if (olength == 1) {
  302.                 result[index++] = '0';
  303.             }

  304.             // Print 'E', the exponent sign, and the exponent, which has at most three digits.
  305.             result[index++] = 'E';
  306.             if (exp < 0) {
  307.                 result[index++] = '-';
  308.                 exp = -exp;
  309.             }
  310.             if (exp >= 100) {
  311.                 result[index++] = (char) ('0' + exp / 100);
  312.                 exp %= 100;
  313.                 result[index++] = (char) ('0' + exp / 10);
  314.             } else if (exp >= 10) {
  315.                 result[index++] = (char) ('0' + exp / 10);
  316.             }
  317.             result[index++] = (char) ('0' + exp % 10);
  318.             return String.valueOf(result, 0, index);
  319.         } else {
  320.             // Otherwise follow the Java spec for values in the interval [10^lowExp, 10^highExp).
  321.             if (exp < 0) {
  322.                 // Decimal dot is before any of the digits.
  323.                 result[index++] = '0';
  324.                 result[index++] = '.';
  325.                 for (int i = -1; i > exp; i--) {
  326.                     result[index++] = '0';
  327.                 }
  328.                 int current = index;
  329.                 for (int i = 0; i < olength; i++) {
  330.                     result[current + olength - i - 1] = (char) ('0' + output % 10);
  331.                     output /= 10;
  332.                     index++;
  333.                 }
  334.             } else if (exp + 1 >= olength) {
  335.                 // Decimal dot is after any of the digits.
  336.                 for (int i = 0; i < olength; i++) {
  337.                     result[index + olength - i - 1] = (char) ('0' + output % 10);
  338.                     output /= 10;
  339.                 }
  340.                 index += olength;
  341.                 for (int i = olength; i < exp + 1; i++) {
  342.                     result[index++] = '0';
  343.                 }
  344.                 result[index++] = '.';
  345.                 result[index++] = '0';
  346.             } else {
  347.                 // Decimal dot is somewhere between the digits.
  348.                 int current = index + 1;
  349.                 for (int i = 0; i < olength; i++) {
  350.                     if (olength - i - 1 == exp) {
  351.                         result[current + olength - i - 1] = '.';
  352.                         current--;
  353.                     }
  354.                     result[current + olength - i - 1] = (char) ('0' + output % 10);
  355.                     output /= 10;
  356.                 }
  357.                 index += olength + 1;
  358.             }
  359.             return String.valueOf(result, 0, index);
  360.         }
  361.     }

  362.     /** Get the number of bits of 5<sup>e</sup>.
  363.      * @param e exponent
  364.      * @return number of bits of 5<sup>e</sup>
  365.      */
  366.     private static int pow5bits(int e) {
  367.         return ((e * 1217359) >>> 19) + 1;
  368.     }

  369.     /** Compute decimal length of an integer.
  370.      * @param v integer to check
  371.      * @return decimal length of {@code v}
  372.      */
  373.     private static int decimalLength(long v) {
  374.         if (v >= 1000000000000000000L) {
  375.             return 19;
  376.         }
  377.         if (v >= 100000000000000000L) {
  378.             return 18;
  379.         }
  380.         if (v >= 10000000000000000L) {
  381.             return 17;
  382.         }
  383.         if (v >= 1000000000000000L) {
  384.             return 16;
  385.         }
  386.         if (v >= 100000000000000L) {
  387.             return 15;
  388.         }
  389.         if (v >= 10000000000000L) {
  390.             return 14;
  391.         }
  392.         if (v >= 1000000000000L) {
  393.             return 13;
  394.         }
  395.         if (v >= 100000000000L) {
  396.             return 12;
  397.         }
  398.         if (v >= 10000000000L) {
  399.             return 11;
  400.         }
  401.         if (v >= 1000000000L) {
  402.             return 10;
  403.         }
  404.         if (v >= 100000000L) {
  405.             return 9;
  406.         }
  407.         if (v >= 10000000L) {
  408.             return 8;
  409.         }
  410.         if (v >= 1000000L) {
  411.             return 7;
  412.         }
  413.         if (v >= 100000L) {
  414.             return 6;
  415.         }
  416.         if (v >= 10000L) {
  417.             return 5;
  418.         }
  419.         if (v >= 1000L) {
  420.             return 4;
  421.         }
  422.         if (v >= 100L) {
  423.             return 3;
  424.         }
  425.         if (v >= 10L) {
  426.             return 2;
  427.         }
  428.         return 1;
  429.     }

  430.     private static boolean multipleOfPowerOf5(long value, int q) {
  431.         return pow5Factor(value) >= q;
  432.     }

  433.     /** Compute largest power of 5 that divides the value.
  434.      * @param value value to check
  435.      * @return largest power of 5 that divides the value
  436.      */
  437.     private static int pow5Factor(long value) {
  438.         // We want to find the largest power of 5 that divides value.
  439.         if ((value % 5) != 0) {
  440.             return 0;
  441.         }
  442.         if ((value % 25) != 0) {
  443.             return 1;
  444.         }
  445.         if ((value % 125) != 0) {
  446.             return 2;
  447.         }
  448.         if ((value % 625) != 0) {
  449.             return 3;
  450.         }
  451.         int count = 4;
  452.         value /= 625;
  453.         while (value > 0) {
  454.             if (value % 5 != 0) {
  455.                 return count;
  456.             }
  457.             value /= 5;
  458.             count++;
  459.         }
  460.         throw new MathIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_SMALL, value, 0);
  461.     }

  462.     /**
  463.      * Compute the high digits of m * 5^p / 10^q = m * 5^(p - q) / 2^q = m * 5^i / 2^j, with q chosen
  464.      * such that m * 5^i / 2^j has sufficiently many decimal digits to represent the original floating
  465.      * point number.
  466.      * @param m mantissa
  467.      * @param i power of 5
  468.      * @param j power of 2
  469.      * @return high digits of m * 5^i / 2^j
  470.      */
  471.     private static long mulPow5divPow2(final long m, final int i, final int j) {
  472.         // m has at most 55 bits.
  473.         long mHigh = m >>> 31;
  474.         long mLow = m & 0x7fffffff;
  475.         long bits13 = mHigh * POW5_SPLIT[i][0]; // 124
  476.         long bits03 = mLow * POW5_SPLIT[i][0];  // 93
  477.         long bits12 = mHigh * POW5_SPLIT[i][1]; // 93
  478.         long bits02 = mLow * POW5_SPLIT[i][1];  // 62
  479.         long bits11 = mHigh * POW5_SPLIT[i][2]; // 62
  480.         long bits01 = mLow * POW5_SPLIT[i][2];  // 31
  481.         long bits10 = mHigh * POW5_SPLIT[i][3]; // 31
  482.         long bits00 = mLow * POW5_SPLIT[i][3];  // 0
  483.         int actualShift = j - 3 * 31 - 21;
  484.         if (actualShift < 0) {
  485.             throw new MathIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_SMALL,
  486.                                                    j, 3 * 31 + 21);
  487.         }
  488.         return ((((((((bits00 >>> 31) + bits01 + bits10) >>> 31) +
  489.                         bits02 + bits11) >>> 31) +
  490.                         bits03 + bits12) >>> 21) +
  491.                         (bits13 << 10)) >>> actualShift;
  492.     }

  493.     /**
  494.      * Compute the high digits of m / 5^i / 2^j such that the result is accurate to at least 9
  495.      * decimal digits. i and j are already chosen appropriately.
  496.      * @param m mantissa
  497.      * @param i power of 5
  498.      * @param j power of 2
  499.      * @return high digits of m / 5^i / 2^j
  500.      */
  501.     private static long mulPow5InvDivPow2(final long m, final int i, final int j) {
  502.         // m has at most 55 bits.
  503.         final long mHigh = m >>> 31;
  504.         final long mLow = m & 0x7fffffff;
  505.         final long bits13 = mHigh * POW5_INV_SPLIT[i][0];
  506.         final long bits03 = mLow * POW5_INV_SPLIT[i][0];
  507.         final long bits12 = mHigh * POW5_INV_SPLIT[i][1];
  508.         final long bits02 = mLow * POW5_INV_SPLIT[i][1];
  509.         final long bits11 = mHigh * POW5_INV_SPLIT[i][2];
  510.         final long bits01 = mLow * POW5_INV_SPLIT[i][2];
  511.         final long bits10 = mHigh * POW5_INV_SPLIT[i][3];
  512.         final long bits00 = mLow * POW5_INV_SPLIT[i][3];

  513.         final int actualShift = j - 3 * 31 - 21;
  514.         if (actualShift < 0) {
  515.             throw new MathIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_SMALL,
  516.                                                    j, 3 * 31 + 21);
  517.         }
  518.         return ((((((((bits00 >>> 31) + bits01 + bits10) >>> 31) +
  519.                         bits02 + bits11) >>> 31) +
  520.                         bits03 + bits12) >>> 21) +
  521.                         (bits13 << 10)) >>> actualShift;
  522.     }

  523. }