1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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
32
33
34
35
36
37
38
39
40 public final class RyuDouble {
41
42
43 public static final int DEFAULT_LOW_EXP = -3;
44
45
46 public static final int DEFAULT_HIGH_EXP = 7;
47
48
49 private static final int DOUBLE_MANTISSA_BITS = 52;
50
51
52 private static final long DOUBLE_MANTISSA_MASK = (1L << DOUBLE_MANTISSA_BITS) - 1;
53
54
55 private static final int DOUBLE_EXPONENT_BITS = 11;
56
57
58 private static final int DOUBLE_EXPONENT_MASK = (1 << DOUBLE_EXPONENT_BITS) - 1;
59
60
61 private static final int DOUBLE_EXPONENT_BIAS = (1 << (DOUBLE_EXPONENT_BITS - 1)) - 1;
62
63
64 private static final int POS_TABLE_SIZE = 326;
65
66
67 private static final int NEG_TABLE_SIZE = 291;
68
69
70 private static final int POW5_BITCOUNT = 121;
71
72
73 private static final int POW5_QUARTER_BITCOUNT = 31;
74
75
76 private static final int[][] POW5_SPLIT = new int[POS_TABLE_SIZE][4];
77
78
79 private static final int POW5_INV_BITCOUNT = 122;
80
81
82 private static final int POW5_INV_QUARTER_BITCOUNT = 31;
83
84
85 private static final int[][] POW5_INV_SPLIT = new int[NEG_TABLE_SIZE][4];
86
87
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
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
119
120 private RyuDouble() {
121
122 }
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137 public static String doubleToString(double value) {
138 return doubleToString(value, DEFAULT_LOW_EXP, DEFAULT_HIGH_EXP);
139 }
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155 public static String doubleToString(double value, int lowExp, int highExp) {
156
157
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
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
182 e2 = 1 - DOUBLE_EXPONENT_BIAS - DOUBLE_MANTISSA_BITS;
183 m2 = ieeeMantissa;
184 } else {
185
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
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
201
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
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
249
250
251
252
253
254
255
256 final int vplength = decimalLength(dp);
257 int exp = e10 + vplength - 1;
258
259
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
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
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
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
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
317
318
319 char[] result = new char[14 - lowExp + highExp];
320 int index = 0;
321 if (sign) {
322 result[index++] = '-';
323 }
324
325
326 if (scientificNotation) {
327
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
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
357 if (exp < 0) {
358
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
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
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
400
401
402
403 private static int pow5bits(int e) {
404 return ((e * 1217359) >>> 19) + 1;
405 }
406
407
408
409
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
474
475
476
477 private static int pow5Factor(long value) {
478
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
505
506
507
508
509
510
511
512 private static long mulPow5divPow2(final long m, final int i, final int j) {
513
514 long mHigh = m >>> 31;
515 long mLow = m & 0x7fffffff;
516 long bits13 = mHigh * POW5_SPLIT[i][0];
517 long bits03 = mLow * POW5_SPLIT[i][0];
518 long bits12 = mHigh * POW5_SPLIT[i][1];
519 long bits02 = mLow * POW5_SPLIT[i][1];
520 long bits11 = mHigh * POW5_SPLIT[i][2];
521 long bits01 = mLow * POW5_SPLIT[i][2];
522 long bits10 = mHigh * POW5_SPLIT[i][3];
523 long bits00 = mLow * POW5_SPLIT[i][3];
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
537
538
539
540
541
542
543 private static long mulPow5InvDivPow2(final long m, final int i, final int j) {
544
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 }