1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.math3.util;
18
19 import java.io.PrintStream;
20
21 import org.apache.commons.math3.exception.DimensionMismatchException;
22
23
24
25
26
27 class FastMathCalc {
28
29
30
31
32
33 private static final long HEX_40000000 = 0x40000000L;
34
35
36 private static final double FACT[] = new double[]
37 {
38 +1.0d,
39 +1.0d,
40 +2.0d,
41 +6.0d,
42 +24.0d,
43 +120.0d,
44 +720.0d,
45 +5040.0d,
46 +40320.0d,
47 +362880.0d,
48 +3628800.0d,
49 +39916800.0d,
50 +479001600.0d,
51 +6227020800.0d,
52 +87178291200.0d,
53 +1307674368000.0d,
54 +20922789888000.0d,
55 +355687428096000.0d,
56 +6402373705728000.0d,
57 +121645100408832000.0d,
58 };
59
60
61 private static final double LN_SPLIT_COEF[][] = {
62 {2.0, 0.0},
63 {0.6666666269302368, 3.9736429850260626E-8},
64 {0.3999999761581421, 2.3841857910019882E-8},
65 {0.2857142686843872, 1.7029898543501842E-8},
66 {0.2222222089767456, 1.3245471311735498E-8},
67 {0.1818181574344635, 2.4384203044354907E-8},
68 {0.1538461446762085, 9.140260083262505E-9},
69 {0.13333332538604736, 9.220590270857665E-9},
70 {0.11764700710773468, 1.2393345855018391E-8},
71 {0.10526403784751892, 8.251545029714408E-9},
72 {0.0952233225107193, 1.2675934823758863E-8},
73 {0.08713622391223907, 1.1430250008909141E-8},
74 {0.07842259109020233, 2.404307984052299E-9},
75 {0.08371849358081818, 1.176342548272881E-8},
76 {0.030589580535888672, 1.2958646899018938E-9},
77 {0.14982303977012634, 1.225743062930824E-8},
78 };
79
80
81 private static final String TABLE_START_DECL = " {";
82
83
84 private static final String TABLE_END_DECL = " };";
85
86
87
88
89 private FastMathCalc() {
90 }
91
92
93
94
95
96
97
98
99
100
101 @SuppressWarnings("unused")
102 private static void buildSinCosTables(double[] SINE_TABLE_A, double[] SINE_TABLE_B,
103 double[] COSINE_TABLE_A, double[] COSINE_TABLE_B,
104 int SINE_TABLE_LEN, double[] TANGENT_TABLE_A, double[] TANGENT_TABLE_B) {
105 final double result[] = new double[2];
106
107
108 for (int i = 0; i < 7; i++) {
109 double x = i / 8.0;
110
111 slowSin(x, result);
112 SINE_TABLE_A[i] = result[0];
113 SINE_TABLE_B[i] = result[1];
114
115 slowCos(x, result);
116 COSINE_TABLE_A[i] = result[0];
117 COSINE_TABLE_B[i] = result[1];
118 }
119
120
121 for (int i = 7; i < SINE_TABLE_LEN; i++) {
122 double xs[] = new double[2];
123 double ys[] = new double[2];
124 double as[] = new double[2];
125 double bs[] = new double[2];
126 double temps[] = new double[2];
127
128 if ( (i & 1) == 0) {
129
130 xs[0] = SINE_TABLE_A[i/2];
131 xs[1] = SINE_TABLE_B[i/2];
132 ys[0] = COSINE_TABLE_A[i/2];
133 ys[1] = COSINE_TABLE_B[i/2];
134
135
136 splitMult(xs, ys, result);
137 SINE_TABLE_A[i] = result[0] * 2.0;
138 SINE_TABLE_B[i] = result[1] * 2.0;
139
140
141 splitMult(ys, ys, as);
142 splitMult(xs, xs, temps);
143 temps[0] = -temps[0];
144 temps[1] = -temps[1];
145 splitAdd(as, temps, result);
146 COSINE_TABLE_A[i] = result[0];
147 COSINE_TABLE_B[i] = result[1];
148 } else {
149 xs[0] = SINE_TABLE_A[i/2];
150 xs[1] = SINE_TABLE_B[i/2];
151 ys[0] = COSINE_TABLE_A[i/2];
152 ys[1] = COSINE_TABLE_B[i/2];
153 as[0] = SINE_TABLE_A[i/2+1];
154 as[1] = SINE_TABLE_B[i/2+1];
155 bs[0] = COSINE_TABLE_A[i/2+1];
156 bs[1] = COSINE_TABLE_B[i/2+1];
157
158
159 splitMult(xs, bs, temps);
160 splitMult(ys, as, result);
161 splitAdd(result, temps, result);
162 SINE_TABLE_A[i] = result[0];
163 SINE_TABLE_B[i] = result[1];
164
165
166 splitMult(ys, bs, result);
167 splitMult(xs, as, temps);
168 temps[0] = -temps[0];
169 temps[1] = -temps[1];
170 splitAdd(result, temps, result);
171 COSINE_TABLE_A[i] = result[0];
172 COSINE_TABLE_B[i] = result[1];
173 }
174 }
175
176
177 for (int i = 0; i < SINE_TABLE_LEN; i++) {
178 double xs[] = new double[2];
179 double ys[] = new double[2];
180 double as[] = new double[2];
181
182 as[0] = COSINE_TABLE_A[i];
183 as[1] = COSINE_TABLE_B[i];
184
185 splitReciprocal(as, ys);
186
187 xs[0] = SINE_TABLE_A[i];
188 xs[1] = SINE_TABLE_B[i];
189
190 splitMult(xs, ys, as);
191
192 TANGENT_TABLE_A[i] = as[0];
193 TANGENT_TABLE_B[i] = as[1];
194 }
195
196 }
197
198
199
200
201
202
203
204
205
206 static double slowCos(final double x, final double result[]) {
207
208 final double xs[] = new double[2];
209 final double ys[] = new double[2];
210 final double facts[] = new double[2];
211 final double as[] = new double[2];
212 split(x, xs);
213 ys[0] = ys[1] = 0.0;
214
215 for (int i = FACT.length-1; i >= 0; i--) {
216 splitMult(xs, ys, as);
217 ys[0] = as[0]; ys[1] = as[1];
218
219 if ( (i & 1) != 0) {
220 continue;
221 }
222
223 split(FACT[i], as);
224 splitReciprocal(as, facts);
225
226 if ( (i & 2) != 0 ) {
227 facts[0] = -facts[0];
228 facts[1] = -facts[1];
229 }
230
231 splitAdd(ys, facts, as);
232 ys[0] = as[0]; ys[1] = as[1];
233 }
234
235 if (result != null) {
236 result[0] = ys[0];
237 result[1] = ys[1];
238 }
239
240 return ys[0] + ys[1];
241 }
242
243
244
245
246
247
248
249
250
251 static double slowSin(final double x, final double result[]) {
252 final double xs[] = new double[2];
253 final double ys[] = new double[2];
254 final double facts[] = new double[2];
255 final double as[] = new double[2];
256 split(x, xs);
257 ys[0] = ys[1] = 0.0;
258
259 for (int i = FACT.length-1; i >= 0; i--) {
260 splitMult(xs, ys, as);
261 ys[0] = as[0]; ys[1] = as[1];
262
263 if ( (i & 1) == 0) {
264 continue;
265 }
266
267 split(FACT[i], as);
268 splitReciprocal(as, facts);
269
270 if ( (i & 2) != 0 ) {
271 facts[0] = -facts[0];
272 facts[1] = -facts[1];
273 }
274
275 splitAdd(ys, facts, as);
276 ys[0] = as[0]; ys[1] = as[1];
277 }
278
279 if (result != null) {
280 result[0] = ys[0];
281 result[1] = ys[1];
282 }
283
284 return ys[0] + ys[1];
285 }
286
287
288
289
290
291
292
293
294
295 static double slowexp(final double x, final double result[]) {
296 final double xs[] = new double[2];
297 final double ys[] = new double[2];
298 final double facts[] = new double[2];
299 final double as[] = new double[2];
300 split(x, xs);
301 ys[0] = ys[1] = 0.0;
302
303 for (int i = FACT.length-1; i >= 0; i--) {
304 splitMult(xs, ys, as);
305 ys[0] = as[0];
306 ys[1] = as[1];
307
308 split(FACT[i], as);
309 splitReciprocal(as, facts);
310
311 splitAdd(ys, facts, as);
312 ys[0] = as[0];
313 ys[1] = as[1];
314 }
315
316 if (result != null) {
317 result[0] = ys[0];
318 result[1] = ys[1];
319 }
320
321 return ys[0] + ys[1];
322 }
323
324
325
326
327
328
329 private static void split(final double d, final double split[]) {
330 if (d < 8e298 && d > -8e298) {
331 final double a = d * HEX_40000000;
332 split[0] = (d + a) - a;
333 split[1] = d - split[0];
334 } else {
335 final double a = d * 9.31322574615478515625E-10;
336 split[0] = (d + a - d) * HEX_40000000;
337 split[1] = d - split[0];
338 }
339 }
340
341
342
343
344
345 private static void resplit(final double a[]) {
346 final double c = a[0] + a[1];
347 final double d = -(c - a[0] - a[1]);
348
349 if (c < 8e298 && c > -8e298) {
350 double z = c * HEX_40000000;
351 a[0] = (c + z) - z;
352 a[1] = c - a[0] + d;
353 } else {
354 double z = c * 9.31322574615478515625E-10;
355 a[0] = (c + z - c) * HEX_40000000;
356 a[1] = c - a[0] + d;
357 }
358 }
359
360
361
362
363
364
365 private static void splitMult(double a[], double b[], double ans[]) {
366 ans[0] = a[0] * b[0];
367 ans[1] = a[0] * b[1] + a[1] * b[0] + a[1] * b[1];
368
369
370 resplit(ans);
371 }
372
373
374
375
376
377
378 private static void splitAdd(final double a[], final double b[], final double ans[]) {
379 ans[0] = a[0] + b[0];
380 ans[1] = a[1] + b[1];
381
382 resplit(ans);
383 }
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403 static void splitReciprocal(final double in[], final double result[]) {
404 final double b = 1.0/4194304.0;
405 final double a = 1.0 - b;
406
407 if (in[0] == 0.0) {
408 in[0] = in[1];
409 in[1] = 0.0;
410 }
411
412 result[0] = a / in[0];
413 result[1] = (b*in[0]-a*in[1]) / (in[0]*in[0] + in[0]*in[1]);
414
415 if (result[1] != result[1]) {
416 result[1] = 0.0;
417 }
418
419
420 resplit(result);
421
422 for (int i = 0; i < 2; i++) {
423
424 double err = 1.0 - result[0] * in[0] - result[0] * in[1] -
425 result[1] * in[0] - result[1] * in[1];
426
427 err = err * (result[0] + result[1]);
428
429 result[1] += err;
430 }
431 }
432
433
434
435
436
437
438 private static void quadMult(final double a[], final double b[], final double result[]) {
439 final double xs[] = new double[2];
440 final double ys[] = new double[2];
441 final double zs[] = new double[2];
442
443
444 split(a[0], xs);
445 split(b[0], ys);
446 splitMult(xs, ys, zs);
447
448 result[0] = zs[0];
449 result[1] = zs[1];
450
451
452 split(b[1], ys);
453 splitMult(xs, ys, zs);
454
455 double tmp = result[0] + zs[0];
456 result[1] = result[1] - (tmp - result[0] - zs[0]);
457 result[0] = tmp;
458 tmp = result[0] + zs[1];
459 result[1] = result[1] - (tmp - result[0] - zs[1]);
460 result[0] = tmp;
461
462
463 split(a[1], xs);
464 split(b[0], ys);
465 splitMult(xs, ys, zs);
466
467 tmp = result[0] + zs[0];
468 result[1] = result[1] - (tmp - result[0] - zs[0]);
469 result[0] = tmp;
470 tmp = result[0] + zs[1];
471 result[1] = result[1] - (tmp - result[0] - zs[1]);
472 result[0] = tmp;
473
474
475 split(a[1], xs);
476 split(b[1], ys);
477 splitMult(xs, ys, zs);
478
479 tmp = result[0] + zs[0];
480 result[1] = result[1] - (tmp - result[0] - zs[0]);
481 result[0] = tmp;
482 tmp = result[0] + zs[1];
483 result[1] = result[1] - (tmp - result[0] - zs[1]);
484 result[0] = tmp;
485 }
486
487
488
489
490
491
492 static double expint(int p, final double result[]) {
493
494 final double xs[] = new double[2];
495 final double as[] = new double[2];
496 final double ys[] = new double[2];
497
498
499
500
501
502
503
504
505 xs[0] = 2.718281828459045;
506 xs[1] = 1.4456468917292502E-16;
507
508 split(1.0, ys);
509
510 while (p > 0) {
511 if ((p & 1) != 0) {
512 quadMult(ys, xs, as);
513 ys[0] = as[0]; ys[1] = as[1];
514 }
515
516 quadMult(xs, xs, as);
517 xs[0] = as[0]; xs[1] = as[1];
518
519 p >>= 1;
520 }
521
522 if (result != null) {
523 result[0] = ys[0];
524 result[1] = ys[1];
525
526 resplit(result);
527 }
528
529 return ys[0] + ys[1];
530 }
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550 static double[] slowLog(double xi) {
551 double x[] = new double[2];
552 double x2[] = new double[2];
553 double y[] = new double[2];
554 double a[] = new double[2];
555
556 split(xi, x);
557
558
559 x[0] += 1.0;
560 resplit(x);
561 splitReciprocal(x, a);
562 x[0] -= 2.0;
563 resplit(x);
564 splitMult(x, a, y);
565 x[0] = y[0];
566 x[1] = y[1];
567
568
569 splitMult(x, x, x2);
570
571
572
573
574
575 y[0] = LN_SPLIT_COEF[LN_SPLIT_COEF.length-1][0];
576 y[1] = LN_SPLIT_COEF[LN_SPLIT_COEF.length-1][1];
577
578 for (int i = LN_SPLIT_COEF.length-2; i >= 0; i--) {
579 splitMult(y, x2, a);
580 y[0] = a[0];
581 y[1] = a[1];
582 splitAdd(y, LN_SPLIT_COEF[i], a);
583 y[0] = a[0];
584 y[1] = a[1];
585 }
586
587 splitMult(y, x, a);
588 y[0] = a[0];
589 y[1] = a[1];
590
591 return y;
592 }
593
594
595
596
597
598
599
600
601
602 static void printarray(PrintStream out, String name, int expectedLen, double[][] array2d) {
603 out.println(name);
604 checkLen(expectedLen, array2d.length);
605 out.println(TABLE_START_DECL + " ");
606 int i = 0;
607 for(double[] array : array2d) {
608 out.print(" {");
609 for(double d : array) {
610 out.printf("%-25.25s", format(d));
611 }
612 out.println("}, // " + i++);
613 }
614 out.println(TABLE_END_DECL);
615 }
616
617
618
619
620
621
622
623
624 static void printarray(PrintStream out, String name, int expectedLen, double[] array) {
625 out.println(name + "=");
626 checkLen(expectedLen, array.length);
627 out.println(TABLE_START_DECL);
628 for(double d : array){
629 out.printf(" %s%n", format(d));
630 }
631 out.println(TABLE_END_DECL);
632 }
633
634
635
636
637
638 static String format(double d) {
639 if (d != d) {
640 return "Double.NaN,";
641 } else {
642 return ((d >= 0) ? "+" : "") + Double.toString(d) + "d,";
643 }
644 }
645
646
647
648
649
650
651
652 private static void checkLen(int expectedLen, int actual)
653 throws DimensionMismatchException {
654 if (expectedLen != actual) {
655 throw new DimensionMismatchException(actual, expectedLen);
656 }
657 }
658
659 }