View Javadoc
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  /*
19   * This is not the original file distributed by Ulf Adams in project
20   * https://github.com/ulfjack/ryu
21   * It has been modified by the Hipparchus project.
22   */
23  package org.hipparchus.util;
24  
25  import java.math.BigInteger;
26  
27  import org.hipparchus.exception.LocalizedCoreFormats;
28  import org.hipparchus.exception.MathIllegalArgumentException;
29  
30  /**
31   * An implementation of Ryū for double.
32   * <p>
33   * Ryū generates the shortest decimal representation of a floating point number
34   * that maintains round-trip safety. That is, a correct parser can recover the
35   * exact original number. Ryū is very fast (about 10 time faster than {@code
36   * Double.toString()}).
37   * </p>
38   * @see <a href="https://dl.acm.org/citation.cfm?doid=3296979.3192369">Ryū: fast float-to-string conversion</a>
39   */
40  public final class RyuDouble {
41  
42      /** Default low switch level to scientific notation. */
43      public static final int DEFAULT_LOW_EXP = -3;
44  
45      /** Default high switch level to scientific notation. */
46      public static final int DEFAULT_HIGH_EXP = 7;
47  
48      /** Number of bits in a double mantissa. */
49      private static final int DOUBLE_MANTISSA_BITS = 52;
50  
51      /** Bit mask for retrieving mantissa. */
52      private static final long DOUBLE_MANTISSA_MASK = (1L << DOUBLE_MANTISSA_BITS) - 1;
53  
54      /** Number of bits in a double exponant. */
55      private static final int DOUBLE_EXPONENT_BITS = 11;
56  
57      /** Bit mask for retrieving exponent. */
58      private static final int DOUBLE_EXPONENT_MASK = (1 << DOUBLE_EXPONENT_BITS) - 1;
59  
60      /** Bias of the exponent. */
61      private static final int DOUBLE_EXPONENT_BIAS = (1 << (DOUBLE_EXPONENT_BITS - 1)) - 1;
62  
63      /** Size of the factors table for positive exponents. */
64      private static final int POS_TABLE_SIZE = 326;
65  
66      /** Size of the factors table for negative exponents. */
67      private static final int NEG_TABLE_SIZE = 291;
68  
69      /** Bit count for complete entries in the positive exponent tables. */
70      private static final int POW5_BITCOUNT = 121; // max 3*31 = 124
71  
72      /** Bit count for split entries in the positive exponent tables. */
73      private static final int POW5_QUARTER_BITCOUNT = 31;
74  
75      /** Split table for positive exponents. */
76      private static final int[][] POW5_SPLIT = new int[POS_TABLE_SIZE][4];
77  
78      /** Bit count for complete entries in the negative exponent tables. */
79      private static final int POW5_INV_BITCOUNT = 122; // max 3*31 = 124
80  
81      /** Bit count for split entries in the negative exponent tables. */
82      private static final int POW5_INV_QUARTER_BITCOUNT = 31;
83  
84      /** Split table for negative exponents. */
85      private static final int[][] POW5_INV_SPLIT = new int[NEG_TABLE_SIZE][4];
86  
87      /** Create the tables. */
88      static {
89          final BigInteger mask = BigInteger.valueOf(1).shiftLeft(POW5_QUARTER_BITCOUNT).subtract(BigInteger.ONE);
90          final BigInteger invMask = BigInteger.valueOf(1).shiftLeft(POW5_INV_QUARTER_BITCOUNT).subtract(BigInteger.ONE);
91          for (int i = 0; i < FastMath.max(POS_TABLE_SIZE, NEG_TABLE_SIZE); i++) {
92              final BigInteger pow = BigInteger.valueOf(5).pow(i);
93              final int pow5len = pow.bitLength();
94              if (i < POW5_SPLIT.length) {
95                  for (int j = 0; j < 4; j++) {
96                      POW5_SPLIT[i][j] = pow.
97                                         shiftRight(pow5len - POW5_BITCOUNT + (3 - j) * POW5_QUARTER_BITCOUNT).
98                                         and(mask).
99                                         intValueExact();
100                 }
101             }
102 
103             if (i < POW5_INV_SPLIT.length) {
104                 // We want floor(log_2 5^q) here, which is pow5len - 1.
105                 final int j = pow5len - 1 + POW5_INV_BITCOUNT;
106                 final BigInteger inv = BigInteger.ONE.shiftLeft(j).divide(pow).add(BigInteger.ONE);
107                 for (int k = 0; k < 4; k++) {
108                     if (k == 0) {
109                         POW5_INV_SPLIT[i][k] = inv.shiftRight((3 - k) * POW5_INV_QUARTER_BITCOUNT).intValueExact();
110                     } else {
111                         POW5_INV_SPLIT[i][k] = inv.shiftRight((3 - k) * POW5_INV_QUARTER_BITCOUNT).and(invMask).intValueExact();
112                     }
113                 }
114             }
115         }
116     }
117 
118     /** Private constructor for a utility class.
119      */
120     private RyuDouble() {
121         // nothing to do
122     }
123 
124     /** Convert a double to shortest string representation, preserving full accuracy.
125      * <p>
126      * This implementation uses the same specifications as {@code Double.toString()},
127      * i.e. it uses scientific notation if for numbers smaller than 10⁻³ or larger
128      * than 10⁺⁷, and decimal notion in between. That is it call {@link #doubleToString(double,
129      * int, int) doubleToString(value, -3, 7)}.
130      * </p>
131      * @param value double number to convert
132      * @return shortest string representation
133      * @see #doubleToString(double, int, int)
134      * @see #DEFAULT_LOW_EXP
135      * @see #DEFAULT_HIGH_EXP
136      */
137     public static String doubleToString(double value) {
138         return doubleToString(value, DEFAULT_LOW_EXP, DEFAULT_HIGH_EXP);
139     }
140 
141     /** Convert a double to shortest string representation, preserving full accuracy.
142      * <p>
143      * Number inside of the interval [10<sup>lowExp</sup>, 10<sup>highExp</sup>]
144      * are represented using decimal notation, numbers outside of this
145      * range are represented using scientific notation.
146      * </p>
147      * @param value double number to convert
148      * @param lowExp lowest decimal exponent for which decimal notation can be used
149      * @param highExp highest decimal exponent for which decimal notation can be used
150      * @return shortest string representation
151      * @see #doubleToString(double)
152      * @see #DEFAULT_LOW_EXP
153      * @see #DEFAULT_HIGH_EXP
154      */
155     public static String doubleToString(double value, int lowExp, int highExp) {
156         // Step 1: Decode the floating point number, and unify normalized and subnormal cases.
157         // First, handle all the trivial cases.
158         if (Double.isNaN(value)) {
159             return "NaN";
160         }
161         if (value == Double.POSITIVE_INFINITY) {
162             return "Infinity";
163         }
164         if (value == Double.NEGATIVE_INFINITY) {
165             return "-Infinity";
166         }
167         long bits = Double.doubleToLongBits(value);
168         if (bits == 0) {
169             return "0.0";
170         }
171         if (bits == 0x8000000000000000L) {
172             return "-0.0";
173         }
174 
175         // Otherwise extract the mantissa and exponent bits and run the full algorithm.
176         final int ieeeExponent = (int) ((bits >>> DOUBLE_MANTISSA_BITS) & DOUBLE_EXPONENT_MASK);
177         final long ieeeMantissa = bits & DOUBLE_MANTISSA_MASK;
178         int e2;
179         final long m2;
180         if (ieeeExponent == 0) {
181             // Denormal number - no implicit leading 1, and the exponent is 1, not 0.
182             e2 = 1 - DOUBLE_EXPONENT_BIAS - DOUBLE_MANTISSA_BITS;
183             m2 = ieeeMantissa;
184         } else {
185             // Add implicit leading 1.
186             e2 = ieeeExponent - DOUBLE_EXPONENT_BIAS - DOUBLE_MANTISSA_BITS;
187             m2 = ieeeMantissa | (1L << DOUBLE_MANTISSA_BITS);
188         }
189 
190         final boolean sign = bits < 0;
191 
192         // Step 2: Determine the interval of legal decimal representations.
193         final boolean even = (m2 & 1) == 0;
194         final long mv = 4 * m2;
195         final long mp = 4 * m2 + 2;
196         final int mmShift = ((m2 != (1L << DOUBLE_MANTISSA_BITS)) || (ieeeExponent <= 1)) ? 1 : 0;
197         final long mm = 4 * m2 - 1 - mmShift;
198         e2 -= 2;
199 
200         // Step 3: Convert to a decimal power base using 128-bit arithmetic.
201         // -1077 = 1 - 1023 - 53 - 2 <= e_2 - 2 <= 2046 - 1023 - 53 - 2 = 968
202         long dv;
203         long dp;
204         long dm;
205         final int e10;
206         boolean dmIsTrailingZeros = false;
207         boolean dvIsTrailingZeros = false;
208         if (e2 >= 0) {
209             final int q = FastMath.max(0, ((e2 * 78913) >>> 18) - 1);
210             // k = constant + floor(log_2(5^q))
211             final int k = POW5_INV_BITCOUNT + pow5bits(q) - 1;
212             final int i = -e2 + q + k;
213             dv = mulPow5InvDivPow2(mv, q, i);
214             dp = mulPow5InvDivPow2(mp, q, i);
215             dm = mulPow5InvDivPow2(mm, q, i);
216             e10 = q;
217 
218             if (q <= 21) {
219                 if (mv % 5 == 0) {
220                     dvIsTrailingZeros = multipleOfPowerOf5(mv, q);
221                 } else if (even) {
222                     dmIsTrailingZeros = multipleOfPowerOf5(mm, q);
223                 } else if (multipleOfPowerOf5(mp, q)) {
224                     dp--;
225                 }
226             }
227         } else {
228             final int q = FastMath.max(0, ((-e2 * 732923) >>> 20) - 1);
229             final int i = -e2 - q;
230             final int k = pow5bits(i) - POW5_BITCOUNT;
231             final int j = q - k;
232             dv = mulPow5divPow2(mv, i, j);
233             dp = mulPow5divPow2(mp, i, j);
234             dm = mulPow5divPow2(mm, i, j);
235             e10 = q + e2;
236             if (q <= 1) {
237                 dvIsTrailingZeros = true;
238                 if (even) {
239                     dmIsTrailingZeros = mmShift == 1;
240                 } else {
241                     dp--;
242                 }
243             } else if (q < 63) {
244                 dvIsTrailingZeros = (mv & ((1L << (q - 1)) - 1)) == 0;
245             }
246         }
247 
248         // Step 4: Find the shortest decimal representation in the interval of legal representations.
249         //
250         // We do some extra work here in order to follow Float/Double.toString semantics. In particular,
251         // that requires printing in scientific format if and only if the exponent is between lowExp and highExp,
252         // and it requires printing at least two decimal digits.
253         //
254         // Above, we moved the decimal dot all the way to the right, so now we need to count digits to
255         // figure out the correct exponent for scientific notation.
256         final int vplength = decimalLength(dp);
257         int exp = e10 + vplength - 1;
258 
259         // use scientific notation if and only if outside this range.
260         final boolean scientificNotation = !((exp >= lowExp) && (exp < highExp));
261 
262         int removed = 0;
263 
264         int lastRemovedDigit = 0;
265         long output;
266         if (dmIsTrailingZeros || dvIsTrailingZeros) {
267             while (dp / 10 > dm / 10) {
268                 if ((dp < 100) && scientificNotation) {
269                     // Double.toString semantics requires printing at least two digits.
270                     break;
271                 }
272                 dmIsTrailingZeros &= dm % 10 == 0;
273                 dvIsTrailingZeros &= lastRemovedDigit == 0;
274                 lastRemovedDigit = (int) (dv % 10);
275                 dp /= 10;
276                 dv /= 10;
277                 dm /= 10;
278                 removed++;
279             }
280             if (dmIsTrailingZeros && even) {
281                 while (dm % 10 == 0) {
282                     if ((dp < 100) && scientificNotation) {
283                         // Double.toString semantics requires printing at least two digits.
284                         break;
285                     }
286                     dvIsTrailingZeros &= lastRemovedDigit == 0;
287                     lastRemovedDigit = (int) (dv % 10);
288                     dp /= 10;
289                     dv /= 10;
290                     dm /= 10;
291                     removed++;
292                 }
293             }
294             if (dvIsTrailingZeros && (lastRemovedDigit == 5) && (dv % 2 == 0)) {
295                 // Round even if the exact numbers is .....50..0.
296                 lastRemovedDigit = 4;
297             }
298             output = dv +
299                             ((dv == dm && !(dmIsTrailingZeros && even)) || (lastRemovedDigit >= 5) ? 1 : 0);
300         } else {
301             while (dp / 10 > dm / 10) {
302                 if ((dp < 100) && scientificNotation) {
303                     // Double.toString semantics requires printing at least two digits.
304                     break;
305                 }
306                 lastRemovedDigit = (int) (dv % 10);
307                 dp /= 10;
308                 dv /= 10;
309                 dm /= 10;
310                 removed++;
311             }
312             output = dv + ((dv == dm || (lastRemovedDigit >= 5)) ? 1 : 0);
313         }
314         int olength = vplength - removed;
315 
316         // Step 5: Print the decimal representation.
317         // We follow Double.toString semantics here,
318         // but adjusting the boundaries at which we switch to scientific notation
319         char[] result = new char[14 - lowExp + highExp];
320         int index = 0;
321         if (sign) {
322             result[index++] = '-';
323         }
324 
325         // Values in the interval [10^lowExp, 10^highExp) are special.
326         if (scientificNotation) {
327             // Print in the format x.xxxxxE-yy.
328             for (int i = 0; i < olength - 1; i++) {
329                 int c = (int) (output % 10);
330                 output /= 10;
331                 result[index + olength - i] = (char) ('0' + c);
332             }
333             result[index] = (char) ('0' + output % 10);
334             result[index + 1] = '.';
335             index += olength + 1;
336             if (olength == 1) {
337                 result[index++] = '0';
338             }
339 
340             // Print 'E', the exponent sign, and the exponent, which has at most three digits.
341             result[index++] = 'E';
342             if (exp < 0) {
343                 result[index++] = '-';
344                 exp = -exp;
345             }
346             if (exp >= 100) {
347                 result[index++] = (char) ('0' + exp / 100);
348                 exp %= 100;
349                 result[index++] = (char) ('0' + exp / 10);
350             } else if (exp >= 10) {
351                 result[index++] = (char) ('0' + exp / 10);
352             }
353             result[index++] = (char) ('0' + exp % 10);
354             return String.valueOf(result, 0, index);
355         } else {
356             // Otherwise follow the Java spec for values in the interval [10^lowExp, 10^highExp).
357             if (exp < 0) {
358                 // Decimal dot is before any of the digits.
359                 result[index++] = '0';
360                 result[index++] = '.';
361                 for (int i = -1; i > exp; i--) {
362                     result[index++] = '0';
363                 }
364                 int current = index;
365                 for (int i = 0; i < olength; i++) {
366                     result[current + olength - i - 1] = (char) ('0' + output % 10);
367                     output /= 10;
368                     index++;
369                 }
370             } else if (exp + 1 >= olength) {
371                 // Decimal dot is after any of the digits.
372                 for (int i = 0; i < olength; i++) {
373                     result[index + olength - i - 1] = (char) ('0' + output % 10);
374                     output /= 10;
375                 }
376                 index += olength;
377                 for (int i = olength; i < exp + 1; i++) {
378                     result[index++] = '0';
379                 }
380                 result[index++] = '.';
381                 result[index++] = '0';
382             } else {
383                 // Decimal dot is somewhere between the digits.
384                 int current = index + 1;
385                 for (int i = 0; i < olength; i++) {
386                     if (olength - i - 1 == exp) {
387                         result[current + olength - i - 1] = '.';
388                         current--;
389                     }
390                     result[current + olength - i - 1] = (char) ('0' + output % 10);
391                     output /= 10;
392                 }
393                 index += olength + 1;
394             }
395             return String.valueOf(result, 0, index);
396         }
397     }
398 
399     /** Get the number of bits of 5<sup>e</sup>.
400      * @param e exponent
401      * @return number of bits of 5<sup>e</sup>
402      */
403     private static int pow5bits(int e) {
404         return ((e * 1217359) >>> 19) + 1;
405     }
406 
407     /** Compute decimal length of an integer.
408      * @param v integer to check
409      * @return decimal length of {@code v}
410      */
411     private static int decimalLength(long v) {
412         if (v >= 1000000000000000000L) {
413             return 19;
414         }
415         if (v >= 100000000000000000L) {
416             return 18;
417         }
418         if (v >= 10000000000000000L) {
419             return 17;
420         }
421         if (v >= 1000000000000000L) {
422             return 16;
423         }
424         if (v >= 100000000000000L) {
425             return 15;
426         }
427         if (v >= 10000000000000L) {
428             return 14;
429         }
430         if (v >= 1000000000000L) {
431             return 13;
432         }
433         if (v >= 100000000000L) {
434             return 12;
435         }
436         if (v >= 10000000000L) {
437             return 11;
438         }
439         if (v >= 1000000000L) {
440             return 10;
441         }
442         if (v >= 100000000L) {
443             return 9;
444         }
445         if (v >= 10000000L) {
446             return 8;
447         }
448         if (v >= 1000000L) {
449             return 7;
450         }
451         if (v >= 100000L) {
452             return 6;
453         }
454         if (v >= 10000L) {
455             return 5;
456         }
457         if (v >= 1000L) {
458             return 4;
459         }
460         if (v >= 100L) {
461             return 3;
462         }
463         if (v >= 10L) {
464             return 2;
465         }
466         return 1;
467     }
468 
469     private static boolean multipleOfPowerOf5(long value, int q) {
470         return pow5Factor(value) >= q;
471     }
472 
473     /** Compute largest power of 5 that divides the value.
474      * @param value value to check
475      * @return largest power of 5 that divides the value
476      */
477     private static int pow5Factor(long value) {
478         // We want to find the largest power of 5 that divides value.
479         if ((value % 5) != 0) {
480             return 0;
481         }
482         if ((value % 25) != 0) {
483             return 1;
484         }
485         if ((value % 125) != 0) {
486             return 2;
487         }
488         if ((value % 625) != 0) {
489             return 3;
490         }
491         int count = 4;
492         value /= 625;
493         while (value > 0) {
494             if (value % 5 != 0) {
495                 return count;
496             }
497             value /= 5;
498             count++;
499         }
500         throw new MathIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_SMALL, value, 0);
501     }
502 
503     /**
504      * Compute the high digits of m * 5^p / 10^q = m * 5^(p - q) / 2^q = m * 5^i / 2^j, with q chosen
505      * such that m * 5^i / 2^j has sufficiently many decimal digits to represent the original floating
506      * point number.
507      * @param m mantissa
508      * @param i power of 5
509      * @param j power of 2
510      * @return high digits of m * 5^i / 2^j
511      */
512     private static long mulPow5divPow2(final long m, final int i, final int j) {
513         // m has at most 55 bits.
514         long mHigh = m >>> 31;
515         long mLow = m & 0x7fffffff;
516         long bits13 = mHigh * POW5_SPLIT[i][0]; // 124
517         long bits03 = mLow * POW5_SPLIT[i][0];  // 93
518         long bits12 = mHigh * POW5_SPLIT[i][1]; // 93
519         long bits02 = mLow * POW5_SPLIT[i][1];  // 62
520         long bits11 = mHigh * POW5_SPLIT[i][2]; // 62
521         long bits01 = mLow * POW5_SPLIT[i][2];  // 31
522         long bits10 = mHigh * POW5_SPLIT[i][3]; // 31
523         long bits00 = mLow * POW5_SPLIT[i][3];  // 0
524         int actualShift = j - 3 * 31 - 21;
525         if (actualShift < 0) {
526             throw new MathIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_SMALL,
527                                                    j, 3 * 31 + 21);
528         }
529         return ((((((((bits00 >>> 31) + bits01 + bits10) >>> 31) +
530                         bits02 + bits11) >>> 31) +
531                         bits03 + bits12) >>> 21) +
532                         (bits13 << 10)) >>> actualShift;
533     }
534 
535     /**
536      * Compute the high digits of m / 5^i / 2^j such that the result is accurate to at least 9
537      * decimal digits. i and j are already chosen appropriately.
538      * @param m mantissa
539      * @param i power of 5
540      * @param j power of 2
541      * @return high digits of m / 5^i / 2^j
542      */
543     private static long mulPow5InvDivPow2(final long m, final int i, final int j) {
544         // m has at most 55 bits.
545         final long mHigh = m >>> 31;
546         final long mLow = m & 0x7fffffff;
547         final long bits13 = mHigh * POW5_INV_SPLIT[i][0];
548         final long bits03 = mLow * POW5_INV_SPLIT[i][0];
549         final long bits12 = mHigh * POW5_INV_SPLIT[i][1];
550         final long bits02 = mLow * POW5_INV_SPLIT[i][1];
551         final long bits11 = mHigh * POW5_INV_SPLIT[i][2];
552         final long bits01 = mLow * POW5_INV_SPLIT[i][2];
553         final long bits10 = mHigh * POW5_INV_SPLIT[i][3];
554         final long bits00 = mLow * POW5_INV_SPLIT[i][3];
555 
556         final int actualShift = j - 3 * 31 - 21;
557         if (actualShift < 0) {
558             throw new MathIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_SMALL,
559                                                    j, 3 * 31 + 21);
560         }
561         return ((((((((bits00 >>> 31) + bits01 + bits10) >>> 31) +
562                         bits02 + bits11) >>> 31) +
563                         bits03 + bits12) >>> 21) +
564                         (bits13 << 10)) >>> actualShift;
565     }
566 
567 }