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.dfp;
24
25
26
27
28 public class DfpMath {
29
30
31 private static final String POW_TRAP = "pow";
32
33
34
35
36 private DfpMath() {
37 }
38
39
40
41
42
43
44
45
46
47
48 protected static Dfp[] split(final DfpField field, final String a) {
49 Dfp[] result = new Dfp[2];
50 boolean leading = true;
51 int sp = 0;
52 int sig = 0;
53
54 StringBuilder builder1 = new StringBuilder(a.length());
55
56 for (int i = 0; i < a.length(); i++) {
57 final char c = a.charAt(i);
58 builder1.append(c);
59
60 if (c >= '1' && c <= '9') {
61 leading = false;
62 }
63
64 if (c == '.') {
65 sig += (400 - sig) % 4;
66 leading = false;
67 }
68
69 if (sig == (field.getRadixDigits() / 2) * 4) {
70 sp = i;
71 break;
72 }
73
74 if (c >= '0' &&c <= '9' && !leading) {
75 sig ++;
76 }
77 }
78
79 result[0] = field.newDfp(builder1.substring(0, sp));
80
81 StringBuilder builder2 = new StringBuilder(a.length());
82 for (int i = 0; i < a.length(); i++) {
83 final char c = a.charAt(i);
84 if (c >= '0' && c <= '9' && i < sp) {
85 builder2.append('0');
86 } else {
87 builder2.append(c);
88 }
89 }
90
91 result[1] = field.newDfp(builder2.toString());
92
93 return result;
94 }
95
96
97
98
99
100 protected static Dfp[] split(final Dfp a) {
101 final Dfp[] result = new Dfp[2];
102 final Dfp shift = a.multiply(a.power10K(a.getRadixDigits() / 2));
103 result[0] = a.add(shift).subtract(shift);
104 result[1] = a.subtract(result[0]);
105 return result;
106 }
107
108
109
110
111
112
113
114
115
116 protected static Dfp[] splitMult(final Dfp[] a, final Dfp[] b) {
117 final Dfp[] result = new Dfp[2];
118
119 result[1] = a[0].getZero();
120 result[0] = a[0].multiply(b[0]);
121
122
123
124
125
126 if (result[0].classify() == Dfp.INFINITE || result[0].equals(result[1])) {
127 return result;
128 }
129
130 result[1] = a[0].multiply(b[1]).add(a[1].multiply(b[0])).add(a[1].multiply(b[1]));
131
132 return result;
133 }
134
135
136
137
138
139
140
141
142 protected static Dfp[] splitDiv(final Dfp[] a, final Dfp[] b) {
143 final Dfp[] result;
144
145 result = new Dfp[2];
146
147 result[0] = a[0].divide(b[0]);
148 result[1] = a[1].multiply(b[0]).subtract(a[0].multiply(b[1]));
149 result[1] = result[1].divide(b[0].multiply(b[0]).add(b[0].multiply(b[1])));
150
151 return result;
152 }
153
154
155
156
157
158
159 protected static Dfp splitPow(final Dfp[] base, int a) {
160 boolean invert = false;
161
162 Dfp[] r = new Dfp[2];
163
164 Dfp[] result = new Dfp[2];
165 result[0] = base[0].getOne();
166 result[1] = base[0].getZero();
167
168 if (a == 0) {
169
170 return result[0].add(result[1]);
171 }
172
173 if (a < 0) {
174
175 invert = true;
176 a = -a;
177 }
178
179
180 do {
181 r[0] = new Dfp(base[0]);
182 r[1] = new Dfp(base[1]);
183 int trial = 1;
184
185 int prevtrial;
186 while (true) {
187 prevtrial = trial;
188 trial *= 2;
189 if (trial > a) {
190 break;
191 }
192 r = splitMult(r, r);
193 }
194
195 trial = prevtrial;
196
197 a -= trial;
198 result = splitMult(result, r);
199
200 } while (a >= 1);
201
202 result[0] = result[0].add(result[1]);
203
204 if (invert) {
205 result[0] = base[0].getOne().divide(result[0]);
206 }
207
208 return result[0];
209
210 }
211
212
213
214
215
216
217 public static Dfp pow(Dfp base, int a)
218 {
219 boolean invert = false;
220
221 Dfp result = base.getOne();
222
223 if (a == 0) {
224
225 return result;
226 }
227
228 if (a < 0) {
229 invert = true;
230 a = -a;
231 }
232
233
234 do {
235 Dfp r = new Dfp(base);
236 Dfp prevr;
237 int trial = 1;
238 int prevtrial;
239
240 do {
241 prevr = new Dfp(r);
242 prevtrial = trial;
243 r = r.square();
244 trial *= 2;
245 } while (a>trial);
246
247 r = prevr;
248 trial = prevtrial;
249
250 a -= trial;
251 result = result.multiply(r);
252
253 } while (a >= 1);
254
255 if (invert) {
256 result = base.getOne().divide(result);
257 }
258
259 return base.newInstance(result);
260
261 }
262
263
264
265
266
267
268
269
270 public static Dfp exp(final Dfp a) {
271
272 final Dfp inta = a.rint();
273 final Dfp fraca = a.subtract(inta);
274
275 final int ia = inta.intValue();
276 if (ia > 2147483646) {
277
278 return a.newInstance((byte)1, Dfp.INFINITE);
279 }
280
281 if (ia < -2147483646) {
282
283 return a.newInstance();
284 }
285
286 final Dfp einta = splitPow(a.getField().getESplit(), ia);
287 final Dfp efraca = expInternal(fraca);
288
289 return einta.multiply(efraca);
290 }
291
292
293
294
295
296
297 protected static Dfp expInternal(final Dfp a) {
298 Dfp y = a.getOne();
299 Dfp x = a.getOne();
300 Dfp fact = a.getOne();
301 Dfp py = new Dfp(y);
302
303 for (int i = 1; i < 90; i++) {
304 x = x.multiply(a);
305 fact = fact.divide(i);
306 y = y.add(x.multiply(fact));
307 if (y.equals(py)) {
308 break;
309 }
310 py = new Dfp(y);
311 }
312
313 return y;
314 }
315
316
317
318
319
320
321
322
323 public static Dfp log(Dfp a) {
324 int lr;
325 Dfp x;
326 int ix;
327 int p2 = 0;
328
329
330 if (a.equals(a.getZero()) || a.lessThan(a.getZero()) || a.isNaN()) {
331
332 a.getField().setIEEEFlagsBits(DfpField.FLAG_INVALID);
333 return a.dotrap(DfpField.FLAG_INVALID, "ln", a, a.newInstance((byte)1, Dfp.QNAN));
334 }
335
336 if (a.classify() == Dfp.INFINITE) {
337 return a;
338 }
339
340 x = new Dfp(a);
341 lr = x.log10K();
342
343 x = x.divide(pow(a.newInstance(10000), lr));
344 ix = x.floor().intValue();
345
346 while (ix > 2) {
347 ix >>= 1;
348 p2++;
349 }
350
351
352 Dfp[] spx = split(x);
353 Dfp[] spy = new Dfp[2];
354 spy[0] = pow(a.getTwo(), p2);
355 spx[0] = spx[0].divide(spy[0]);
356 spx[1] = spx[1].divide(spy[0]);
357
358 spy[0] = a.newInstance("1.33333");
359 while (spx[0].add(spx[1]).greaterThan(spy[0])) {
360 spx[0] = spx[0].divide(2);
361 spx[1] = spx[1].divide(2);
362 p2++;
363 }
364
365
366 Dfp[] spz = logInternal(spx);
367
368 spx[0] = a.newInstance(new StringBuilder().append(p2+4*lr).toString());
369 spx[1] = a.getZero();
370 spy = splitMult(a.getField().getLn2Split(), spx);
371
372 spz[0] = spz[0].add(spy[0]);
373 spz[1] = spz[1].add(spy[1]);
374
375 spx[0] = a.newInstance(new StringBuilder().append(4*lr).toString());
376 spx[1] = a.getZero();
377 spy = splitMult(a.getField().getLn5Split(), spx);
378
379 spz[0] = spz[0].add(spy[0]);
380 spz[1] = spz[1].add(spy[1]);
381
382 return a.newInstance(spz[0].add(spz[1]));
383
384 }
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441 protected static Dfp[] logInternal(final Dfp[] a) {
442
443
444
445
446 Dfp t = a[0].divide(4).add(a[1].divide(4));
447 Dfp x = t.add(a[0].newInstance("-0.25")).divide(t.add(a[0].newInstance("0.25")));
448
449 Dfp y = new Dfp(x);
450 Dfp num = new Dfp(x);
451 Dfp py = new Dfp(y);
452 int den = 1;
453 for (int i = 0; i < 10000; i++) {
454 num = num.multiply(x);
455 num = num.multiply(x);
456 den += 2;
457 t = num.divide(den);
458 y = y.add(t);
459 if (y.equals(py)) {
460 break;
461 }
462 py = new Dfp(y);
463 }
464
465 y = y.multiply(a[0].getTwo());
466
467 return split(y);
468
469 }
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511 public static Dfp pow(Dfp x, final Dfp y) {
512
513
514 if (x.getField().getRadixDigits() != y.getField().getRadixDigits()) {
515 x.getField().setIEEEFlagsBits(DfpField.FLAG_INVALID);
516 final Dfp result = x.newInstance(x.getZero());
517 result.nans = Dfp.QNAN;
518 return x.dotrap(DfpField.FLAG_INVALID, POW_TRAP, x, result);
519 }
520
521 final Dfp zero = x.getZero();
522 final Dfp one = x.getOne();
523 final Dfp two = x.getTwo();
524 boolean invert = false;
525 int ui;
526
527
528 if (y.equals(zero)) {
529 return x.newInstance(one);
530 }
531
532 if (y.equals(one)) {
533 if (x.isNaN()) {
534
535 x.getField().setIEEEFlagsBits(DfpField.FLAG_INVALID);
536 return x.dotrap(DfpField.FLAG_INVALID, POW_TRAP, x, x);
537 }
538 return x;
539 }
540
541 if (x.isNaN() || y.isNaN()) {
542
543 x.getField().setIEEEFlagsBits(DfpField.FLAG_INVALID);
544 return x.dotrap(DfpField.FLAG_INVALID, POW_TRAP, x, x.newInstance((byte)1, Dfp.QNAN));
545 }
546
547
548 if (x.equals(zero)) {
549 if (Dfp.copysign(one, x).greaterThan(zero)) {
550
551 if (y.greaterThan(zero)) {
552 return x.newInstance(zero);
553 } else {
554 return x.newInstance(x.newInstance((byte)1, Dfp.INFINITE));
555 }
556 } else {
557
558 if (y.classify() == Dfp.FINITE && y.rint().equals(y) && !y.remainder(two).equals(zero)) {
559
560 if (y.greaterThan(zero)) {
561 return x.newInstance(zero.negate());
562 } else {
563 return x.newInstance(x.newInstance((byte)-1, Dfp.INFINITE));
564 }
565 } else {
566
567 if (y.greaterThan(zero)) {
568 return x.newInstance(zero);
569 } else {
570 return x.newInstance(x.newInstance((byte)1, Dfp.INFINITE));
571 }
572 }
573 }
574 }
575
576 if (x.lessThan(zero)) {
577
578 x = x.negate();
579 invert = true;
580 }
581
582 if (x.greaterThan(one) && y.classify() == Dfp.INFINITE) {
583 if (y.greaterThan(zero)) {
584 return y;
585 } else {
586 return x.newInstance(zero);
587 }
588 }
589
590 if (x.lessThan(one) && y.classify() == Dfp.INFINITE) {
591 if (y.greaterThan(zero)) {
592 return x.newInstance(zero);
593 } else {
594 return x.newInstance(Dfp.copysign(y, one));
595 }
596 }
597
598 if (x.equals(one) && y.classify() == Dfp.INFINITE) {
599 x.getField().setIEEEFlagsBits(DfpField.FLAG_INVALID);
600 return x.dotrap(DfpField.FLAG_INVALID, POW_TRAP, x, x.newInstance((byte)1, Dfp.QNAN));
601 }
602
603 if (x.classify() == Dfp.INFINITE) {
604
605 if (invert) {
606
607 if (y.classify() == Dfp.FINITE && y.rint().equals(y) && !y.remainder(two).equals(zero)) {
608
609 if (y.greaterThan(zero)) {
610 return x.newInstance(x.newInstance((byte)-1, Dfp.INFINITE));
611 } else {
612 return x.newInstance(zero.negate());
613 }
614 } else {
615
616 if (y.greaterThan(zero)) {
617 return x.newInstance(x.newInstance((byte)1, Dfp.INFINITE));
618 } else {
619 return x.newInstance(zero);
620 }
621 }
622 } else {
623
624 if (y.greaterThan(zero)) {
625 return x;
626 } else {
627 return x.newInstance(zero);
628 }
629 }
630 }
631
632 if (invert && !y.rint().equals(y)) {
633 x.getField().setIEEEFlagsBits(DfpField.FLAG_INVALID);
634 return x.dotrap(DfpField.FLAG_INVALID, POW_TRAP, x, x.newInstance((byte)1, Dfp.QNAN));
635 }
636
637
638
639 Dfp r;
640 if (y.lessThan(x.newInstance(100000000)) && y.greaterThan(x.newInstance(-100000000))) {
641 final Dfp u = y.rint();
642 ui = u.intValue();
643
644 final Dfp v = y.subtract(u);
645
646 if (v.unequal(zero)) {
647 final Dfp a = v.multiply(log(x));
648 final Dfp b = a.divide(x.getField().getLn2()).rint();
649
650 final Dfp c = a.subtract(b.multiply(x.getField().getLn2()));
651 r = splitPow(split(x), ui);
652 r = r.multiply(pow(two, b.intValue()));
653 r = r.multiply(exp(c));
654 } else {
655 r = splitPow(split(x), ui);
656 }
657 } else {
658
659 r = exp(log(x).multiply(y));
660 }
661
662 if (invert && y.rint().equals(y) && !y.remainder(two).equals(zero)) {
663
664 r = r.negate();
665 }
666
667 return x.newInstance(r);
668
669 }
670
671
672
673
674
675
676 protected static Dfp sinInternal(Dfp[] a) {
677
678 Dfp c = a[0].add(a[1]);
679 Dfp y = c;
680 c = c.square();
681 Dfp x = y;
682 Dfp fact = a[0].getOne();
683 Dfp py = new Dfp(y);
684
685 for (int i = 3; i < 90; i += 2) {
686 x = x.multiply(c);
687 x = x.negate();
688
689 fact = fact.divide((i-1)*i);
690 y = y.add(x.multiply(fact));
691 if (y.equals(py)) {
692 break;
693 }
694 py = new Dfp(y);
695 }
696
697 return y;
698
699 }
700
701
702
703
704
705
706 protected static Dfp cosInternal(Dfp[] a) {
707 final Dfp one = a[0].getOne();
708
709
710 Dfp x = one;
711 Dfp y = one;
712 Dfp c = a[0].add(a[1]);
713 c = c.square();
714
715 Dfp fact = one;
716 Dfp py = new Dfp(y);
717
718 for (int i = 2; i < 90; i += 2) {
719 x = x.multiply(c);
720 x = x.negate();
721
722 fact = fact.divide((i - 1) * i);
723
724 y = y.add(x.multiply(fact));
725 if (y.equals(py)) {
726 break;
727 }
728 py = new Dfp(y);
729 }
730
731 return y;
732
733 }
734
735
736
737
738
739 public static Dfp sin(final Dfp a) {
740 final Dfp pi = a.getField().getPi();
741 final Dfp zero = a.getField().getZero();
742 boolean neg = false;
743
744
745 Dfp x = a.remainder(pi.multiply(2));
746
747
748
749 if (x.lessThan(zero)) {
750 x = x.negate();
751 neg = true;
752 }
753
754
755
756
757
758 if (x.greaterThan(pi.divide(2))) {
759 x = pi.subtract(x);
760 }
761
762 Dfp y;
763 if (x.lessThan(pi.divide(4))) {
764 y = sinInternal(split(x));
765 } else {
766 final Dfp[] c = new Dfp[2];
767 final Dfp[] piSplit = a.getField().getPiSplit();
768 c[0] = piSplit[0].divide(2).subtract(x);
769 c[1] = piSplit[1].divide(2);
770 y = cosInternal(c);
771 }
772
773 if (neg) {
774 y = y.negate();
775 }
776
777 return a.newInstance(y);
778
779 }
780
781
782
783
784
785 public static Dfp cos(Dfp a) {
786 final Dfp pi = a.getField().getPi();
787 final Dfp zero = a.getField().getZero();
788 boolean neg = false;
789
790
791 Dfp x = a.remainder(pi.multiply(2));
792
793
794
795 if (x.lessThan(zero)) {
796 x = x.negate();
797 }
798
799
800
801
802
803 if (x.greaterThan(pi.divide(2))) {
804 x = pi.subtract(x);
805 neg = true;
806 }
807
808 Dfp y;
809 if (x.lessThan(pi.divide(4))) {
810 Dfp[] c = new Dfp[2];
811 c[0] = x;
812 c[1] = zero;
813
814 y = cosInternal(c);
815 } else {
816 final Dfp[] c = new Dfp[2];
817 final Dfp[] piSplit = a.getField().getPiSplit();
818 c[0] = piSplit[0].divide(2).subtract(x);
819 c[1] = piSplit[1].divide(2);
820 y = sinInternal(c);
821 }
822
823 if (neg) {
824 y = y.negate();
825 }
826
827 return a.newInstance(y);
828
829 }
830
831
832
833
834
835 public static Dfp tan(final Dfp a) {
836 return sin(a).divide(cos(a));
837 }
838
839
840
841
842
843 protected static Dfp atanInternal(final Dfp a) {
844
845 Dfp y = new Dfp(a);
846 Dfp x = new Dfp(y);
847 Dfp py = new Dfp(y);
848
849 for (int i = 3; i < 90; i += 2) {
850 x = x.multiply(a);
851 x = x.multiply(a);
852 x = x.negate();
853 y = y.add(x.divide(i));
854 if (y.equals(py)) {
855 break;
856 }
857 py = new Dfp(y);
858 }
859
860 return y;
861
862 }
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877 public static Dfp atan(final Dfp a) {
878 final Dfp zero = a.getField().getZero();
879 final Dfp one = a.getField().getOne();
880 final Dfp[] sqr2Split = a.getField().getSqr2Split();
881 final Dfp[] piSplit = a.getField().getPiSplit();
882 boolean recp = false;
883 boolean neg = false;
884 boolean sub = false;
885
886 final Dfp ty = sqr2Split[0].subtract(one).add(sqr2Split[1]);
887
888 Dfp x = new Dfp(a);
889 if (x.lessThan(zero)) {
890 neg = true;
891 x = x.negate();
892 }
893
894 if (x.greaterThan(one)) {
895 recp = true;
896 x = one.divide(x);
897 }
898
899 if (x.greaterThan(ty)) {
900 Dfp[] sty = new Dfp[2];
901 sub = true;
902
903 sty[0] = sqr2Split[0].subtract(one);
904 sty[1] = sqr2Split[1];
905
906 Dfp[] xs = split(x);
907
908 Dfp[] ds = splitMult(xs, sty);
909 ds[0] = ds[0].add(one);
910
911 xs[0] = xs[0].subtract(sty[0]);
912 xs[1] = xs[1].subtract(sty[1]);
913
914 xs = splitDiv(xs, ds);
915 x = xs[0].add(xs[1]);
916
917
918 }
919
920 Dfp y = atanInternal(x);
921
922 if (sub) {
923 y = y.add(piSplit[0].divide(8)).add(piSplit[1].divide(8));
924 }
925
926 if (recp) {
927 y = piSplit[0].divide(2).subtract(y).add(piSplit[1].divide(2));
928 }
929
930 if (neg) {
931 y = y.negate();
932 }
933
934 return a.newInstance(y);
935
936 }
937
938
939
940
941
942 public static Dfp asin(final Dfp a) {
943 return atan(a.divide(a.getOne().subtract(a.square()).sqrt()));
944 }
945
946
947
948
949
950 public static Dfp acos(Dfp a) {
951 Dfp result;
952 boolean negative = false;
953
954 if (a.lessThan(a.getZero())) {
955 negative = true;
956 }
957
958 a = Dfp.copysign(a, a.getOne());
959
960 result = atan(a.getOne().subtract(a.square()).sqrt().divide(a));
961
962 if (negative) {
963 result = a.getField().getPi().subtract(result);
964 }
965
966 return a.newInstance(result);
967 }
968
969 }