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.apache.commons.numbers.gamma;
24
25 import java.util.function.DoubleSupplier;
26 import java.util.function.Supplier;
27 import org.apache.commons.numbers.fraction.GeneralizedContinuedFraction;
28 import org.apache.commons.numbers.fraction.GeneralizedContinuedFraction.Coefficient;
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43 final class BoostBeta {
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71 private static final double EPSILON = 0x1.0p-52;
72
73
74
75
76 private static final int LOG_MAX_VALUE = 709;
77
78
79
80
81 private static final int LOG_MIN_VALUE = -708;
82
83 private static final double HALF_PI = Math.PI / 2;
84
85
86 private static final int MAX_FACTORIAL = 170;
87
88
89 private static final int PN_SIZE = 30;
90
91 private static final double TWO_POW_53 = 0x1.0p53;
92
93 private static final double TWO_POW_M53 = 0x1.0p-53;
94
95
96 private BoostBeta() {
97
98 }
99
100
101
102
103
104
105
106
107
108 static double beta(double p, double q) {
109 if (!(p > 0 && q > 0)) {
110
111 return Double.NaN;
112 }
113
114 final double c = p + q;
115
116
117 if (c == p && q < EPSILON) {
118 return 1 / q;
119 } else if (c == q && p < EPSILON) {
120 return 1 / p;
121 }
122 if (q == 1) {
123 return 1 / p;
124 } else if (p == 1) {
125 return 1 / q;
126 } else if (c < EPSILON) {
127 return (c / p) / q;
128 }
129
130
131 final double a = p < q ? q : p;
132 final double b = p < q ? p : q;
133
134
135 final double agh = a + BoostGamma.Lanczos.GMH;
136 final double bgh = b + BoostGamma.Lanczos.GMH;
137 final double cgh = c + BoostGamma.Lanczos.GMH;
138 double result = BoostGamma.Lanczos.lanczosSumExpGScaled(a) *
139 (BoostGamma.Lanczos.lanczosSumExpGScaled(b) / BoostGamma.Lanczos.lanczosSumExpGScaled(c));
140 final double ambh = a - 0.5f - b;
141 if (Math.abs(b * ambh) < cgh * 100 && a > 100) {
142
143
144 result *= Math.exp(ambh * Math.log1p(-b / cgh));
145 } else {
146 result *= Math.pow(agh / cgh, ambh);
147 }
148
149 if (cgh > 1e10f) {
150
151 result *= Math.pow((agh / cgh) * (bgh / cgh), b);
152 } else {
153 result *= Math.pow((agh * bgh) / (cgh * cgh), b);
154 }
155 result *= Math.sqrt(Math.E / bgh);
156
157 return result;
158 }
159
160
161
162
163
164
165
166
167
168
169
170
171 static double ibetaDerivative(double a, double b, double x) {
172
173
174
175 if (!(a > 0 && b > 0) || !(x >= 0 && x <= 1)) {
176
177 return Double.NaN;
178 }
179
180
181
182 if (x == 0) {
183 if (a > 1) {
184 return 0;
185 }
186
187 return a == 1 ? b : Double.POSITIVE_INFINITY;
188 } else if (x == 1) {
189 if (b > 1) {
190 return 0;
191 }
192
193 return b == 1 ? a : Double.POSITIVE_INFINITY;
194 }
195
196
197 if (b == 1) {
198
199 return a * Math.pow(x, a - 1);
200 }
201 if (a == 1) {
202
203 if (x >= 0.5) {
204 return b * Math.pow(1 - x, b - 1);
205 }
206 return b * Math.exp(Math.log1p(-x) * (b - 1));
207 }
208
209
210
211
212 final double y = (1 - x) * x;
213 return ibetaPowerTerms(a, b, x, 1 - x, true, 1 / y);
214 }
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230 private static double ibetaPowerTerms(double a, double b, double x,
231 double y, boolean normalised) {
232 return ibetaPowerTerms(a, b, x, y, normalised, 1);
233 }
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255 private static double ibetaPowerTerms(double a, double b, double x,
256 double y, boolean normalised, double prefix) {
257 if (!normalised) {
258
259 return Math.pow(x, a) * Math.pow(y, b);
260 }
261
262 double result;
263
264 final double c = a + b;
265
266
267 final double agh = a + BoostGamma.Lanczos.GMH;
268 final double bgh = b + BoostGamma.Lanczos.GMH;
269 final double cgh = c + BoostGamma.Lanczos.GMH;
270 result = BoostGamma.Lanczos.lanczosSumExpGScaled(c) /
271 (BoostGamma.Lanczos.lanczosSumExpGScaled(a) * BoostGamma.Lanczos.lanczosSumExpGScaled(b));
272 result *= prefix;
273
274 result *= Math.sqrt(bgh / Math.E);
275 result *= Math.sqrt(agh / cgh);
276
277
278 double l1 = (x * b - y * agh) / agh;
279 double l2 = (y * a - x * bgh) / bgh;
280 if (Math.min(Math.abs(l1), Math.abs(l2)) < 0.2) {
281
282
283 if (l1 * l2 > 0 || Math.min(a, b) < 1) {
284
285
286
287
288
289
290
291
292
293
294
295
296
297 if (Math.abs(l1) < 0.1) {
298 result *= Math.exp(a * Math.log1p(l1));
299 } else {
300 result *= Math.pow((x * cgh) / agh, a);
301 }
302 if (Math.abs(l2) < 0.1) {
303 result *= Math.exp(b * Math.log1p(l2));
304 } else {
305 result *= Math.pow((y * cgh) / bgh, b);
306 }
307 } else if (Math.max(Math.abs(l1), Math.abs(l2)) < 0.5) {
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327 final boolean smallA = a < b;
328 final double ratio = b / a;
329 if ((smallA && ratio * l2 < 0.1) || (!smallA && l1 / ratio > 0.1)) {
330 double l3 = Math.expm1(ratio * Math.log1p(l2));
331 l3 = l1 + l3 + l3 * l1;
332 l3 = a * Math.log1p(l3);
333 result *= Math.exp(l3);
334 } else {
335 double l3 = Math.expm1(Math.log1p(l1) / ratio);
336 l3 = l2 + l3 + l3 * l2;
337 l3 = b * Math.log1p(l3);
338 result *= Math.exp(l3);
339 }
340 } else if (Math.abs(l1) < Math.abs(l2)) {
341
342 double l = a * Math.log1p(l1) + b * Math.log((y * cgh) / bgh);
343 if (l <= LOG_MIN_VALUE || l >= LOG_MAX_VALUE) {
344 l += Math.log(result);
345
346 result = Math.exp(l);
347 } else {
348 result *= Math.exp(l);
349 }
350 } else {
351
352 double l = b * Math.log1p(l2) + a * Math.log((x * cgh) / agh);
353 if (l <= LOG_MIN_VALUE || l >= LOG_MAX_VALUE) {
354 l += Math.log(result);
355
356 result = Math.exp(l);
357 } else {
358 result *= Math.exp(l);
359 }
360 }
361 } else {
362
363 final double b1 = (x * cgh) / agh;
364 final double b2 = (y * cgh) / bgh;
365 l1 = a * Math.log(b1);
366 l2 = b * Math.log(b2);
367 if (l1 >= LOG_MAX_VALUE || l1 <= LOG_MIN_VALUE || l2 >= LOG_MAX_VALUE || l2 <= LOG_MIN_VALUE) {
368
369 if (a < b) {
370 final double p1 = Math.pow(b2, b / a);
371 final double l3 = a * (Math.log(b1) + Math.log(p1));
372 if (l3 < LOG_MAX_VALUE && l3 > LOG_MIN_VALUE) {
373 result *= Math.pow(p1 * b1, a);
374 } else {
375 l2 += l1 + Math.log(result);
376
377 result = Math.exp(l2);
378 }
379 } else {
380 final double p1 = Math.pow(b1, a / b);
381 final double l3 = (Math.log(p1) + Math.log(b2)) * b;
382 if (l3 < LOG_MAX_VALUE && l3 > LOG_MIN_VALUE) {
383 result *= Math.pow(p1 * b2, b);
384 } else {
385 l2 += l1 + Math.log(result);
386
387 result = Math.exp(l2);
388 }
389 }
390 } else {
391
392 result *= Math.pow(b1, a) * Math.pow(b2, b);
393 }
394 }
395
396 return result;
397 }
398
399
400
401
402
403
404
405
406
407
408 static double beta(double a, double b, double x) {
409 return betaIncompleteImp(a, b, x, Policy.getDefault(), false, false);
410 }
411
412
413
414
415
416
417
418
419
420
421
422 static double beta(double a, double b, double x, Policy policy) {
423 return betaIncompleteImp(a, b, x, policy, false, false);
424 }
425
426
427
428
429
430
431
432
433
434
435 static double betac(double a, double b, double x) {
436 return betaIncompleteImp(a, b, x, Policy.getDefault(), false, true);
437 }
438
439
440
441
442
443
444
445
446
447
448
449 static double betac(double a, double b, double x, Policy policy) {
450 return betaIncompleteImp(a, b, x, policy, false, true);
451 }
452
453
454
455
456
457
458
459
460
461
462 static double ibeta(double a, double b, double x) {
463 return betaIncompleteImp(a, b, x, Policy.getDefault(), true, false);
464 }
465
466
467
468
469
470
471
472
473
474
475
476 static double ibeta(double a, double b, double x, Policy policy) {
477 return betaIncompleteImp(a, b, x, policy, true, false);
478 }
479
480
481
482
483
484
485
486
487
488
489 static double ibetac(double a, double b, double x) {
490 return betaIncompleteImp(a, b, x, Policy.getDefault(), true, true);
491 }
492
493
494
495
496
497
498
499
500
501
502
503 static double ibetac(double a, double b, double x, Policy policy) {
504 return betaIncompleteImp(a, b, x, policy, true, true);
505 }
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523 private static double betaIncompleteImp(double a, double b, double x,
524 Policy pol, boolean normalised, boolean inv) {
525
526
527
528
529
530
531
532 if (!(x >= 0 && x <= 1)) {
533
534 return Double.NaN;
535 }
536
537 if (normalised) {
538 if (!(a >= 0 && b >= 0)) {
539
540 return Double.NaN;
541 }
542
543 if (a == 0) {
544 if (b == 0) {
545
546 return Double.NaN;
547 }
548
549 return inv ? 0 : 1;
550 } else if (b == 0) {
551
552 return inv ? 1 : 0;
553 }
554 } else {
555 if (!(a > 0 && b > 0)) {
556
557 return Double.NaN;
558 }
559 }
560
561 if (x == 0) {
562 if (inv) {
563 return normalised ? 1 : beta(a, b);
564 }
565 return 0;
566 }
567 if (x == 1) {
568 if (!inv) {
569 return normalised ? 1 : beta(a, b);
570 }
571 return 0;
572 }
573
574 if (a == 0.5f && b == 0.5f) {
575
576 final double z = inv ? 1 - x : x;
577 final double asin = Math.asin(Math.sqrt(z));
578 return normalised ? asin / HALF_PI : 2 * asin;
579 }
580
581 boolean invert = inv;
582 double y = 1 - x;
583 if (a == 1) {
584
585 double tmp = a;
586 a = b;
587 b = tmp;
588
589 tmp = x;
590 x = y;
591 y = tmp;
592 invert = !invert;
593 }
594 if (b == 1) {
595
596
597
598
599 if (a == 1) {
600 return invert ? y : x;
601 }
602
603 double p;
604 if (y < 0.5) {
605 p = invert ? -Math.expm1(a * Math.log1p(-y)) : Math.exp(a * Math.log1p(-y));
606 } else {
607 p = invert ? -BoostMath.powm1(x, a) : Math.pow(x, a);
608 }
609 if (!normalised) {
610 p /= a;
611 }
612 return p;
613 }
614
615 double fract;
616 if (Math.min(a, b) <= 1) {
617 if (x > 0.5) {
618
619 double tmp = a;
620 a = b;
621 b = tmp;
622
623 tmp = x;
624 x = y;
625 y = tmp;
626 invert = !invert;
627 }
628 if (Math.max(a, b) <= 1) {
629
630 if (a >= Math.min(0.2, b) || Math.pow(x, a) <= 0.9) {
631 if (invert) {
632 fract = -(normalised ? 1 : beta(a, b));
633 invert = false;
634 fract = -ibetaSeries(a, b, x, fract, normalised, pol);
635 } else {
636 fract = ibetaSeries(a, b, x, 0, normalised, pol);
637 }
638 } else {
639
640 double tmp = a;
641 a = b;
642 b = tmp;
643
644 tmp = x;
645 x = y;
646 y = tmp;
647 invert = !invert;
648 if (y >= 0.3) {
649 if (invert) {
650 fract = -(normalised ? 1 : beta(a, b));
651 invert = false;
652 fract = -ibetaSeries(a, b, x, fract, normalised, pol);
653 } else {
654 fract = ibetaSeries(a, b, x, 0, normalised, pol);
655 }
656 } else {
657
658 final double prefix;
659 if (normalised) {
660 prefix = 1;
661 } else {
662 prefix = risingFactorialRatio(a + b, a, 20);
663 }
664 fract = ibetaAStep(a, b, x, y, 20, normalised);
665 if (invert) {
666 fract -= normalised ? 1 : beta(a, b);
667 invert = false;
668 fract = -betaSmallBLargeASeries(a + 20, b, x, y, fract, prefix, pol, normalised);
669 } else {
670 fract = betaSmallBLargeASeries(a + 20, b, x, y, fract, prefix, pol, normalised);
671 }
672 }
673 }
674 } else {
675
676 if (b <= 1 || (x < 0.1 && Math.pow(b * x, a) <= 0.7)) {
677 if (invert) {
678 fract = -(normalised ? 1 : beta(a, b));
679 invert = false;
680 fract = -ibetaSeries(a, b, x, fract, normalised, pol);
681 } else {
682 fract = ibetaSeries(a, b, x, 0, normalised, pol);
683 }
684 } else {
685
686 double tmp = a;
687 a = b;
688 b = tmp;
689
690 tmp = x;
691 x = y;
692 y = tmp;
693 invert = !invert;
694
695 if (y >= 0.3) {
696 if (invert) {
697 fract = -(normalised ? 1 : beta(a, b));
698 invert = false;
699 fract = -ibetaSeries(a, b, x, fract, normalised, pol);
700 } else {
701 fract = ibetaSeries(a, b, x, 0, normalised, pol);
702 }
703 } else if (a >= 15) {
704 if (invert) {
705 fract = -(normalised ? 1 : beta(a, b));
706 invert = false;
707 fract = -betaSmallBLargeASeries(a, b, x, y, fract, 1, pol, normalised);
708 } else {
709 fract = betaSmallBLargeASeries(a, b, x, y, 0, 1, pol, normalised);
710 }
711 } else {
712
713 final double prefix;
714 if (normalised) {
715 prefix = 1;
716 } else {
717 prefix = risingFactorialRatio(a + b, a, 20);
718 }
719 fract = ibetaAStep(a, b, x, y, 20, normalised);
720 if (invert) {
721 fract -= normalised ? 1 : beta(a, b);
722 invert = false;
723 fract = -betaSmallBLargeASeries(a + 20, b, x, y, fract, prefix, pol, normalised);
724 } else {
725 fract = betaSmallBLargeASeries(a + 20, b, x, y, fract, prefix, pol, normalised);
726 }
727 }
728 }
729 }
730 } else {
731
732
733
734
735 final double lambda;
736 if (a < b) {
737 lambda = a - (a + b) * x;
738 } else {
739 lambda = (a + b) * y - b;
740 }
741 if (lambda < 0) {
742
743 double tmp = a;
744 a = b;
745 b = tmp;
746
747 tmp = x;
748 x = y;
749 y = tmp;
750 invert = !invert;
751 }
752
753 if (b < 40) {
754
755 if (Math.rint(a) == a && Math.rint(b) == b && a < (Integer.MAX_VALUE - 100) && y != 1) {
756
757
758
759 final int k = (int) (a - 1);
760 final int n = (int) (b + k);
761 fract = binomialCCdf(n, k, x, y);
762 if (!normalised) {
763 fract *= beta(a, b);
764 }
765 } else if (b * x <= 0.7) {
766 if (invert) {
767 fract = -(normalised ? 1 : beta(a, b));
768 invert = false;
769 fract = -ibetaSeries(a, b, x, fract, normalised, pol);
770 } else {
771 fract = ibetaSeries(a, b, x, 0, normalised, pol);
772 }
773 } else if (a > 15) {
774
775 int n = (int) b;
776 if (n == b) {
777 --n;
778 }
779 final double bbar = b - n;
780 final double prefix;
781 if (normalised) {
782 prefix = 1;
783 } else {
784 prefix = risingFactorialRatio(a + bbar, bbar, n);
785 }
786 fract = ibetaAStep(bbar, a, y, x, n, normalised);
787 fract = betaSmallBLargeASeries(a, bbar, x, y, fract, 1, pol, normalised);
788 fract /= prefix;
789 } else if (normalised) {
790
791
792
793 int n = (int) Math.floor(b);
794 double bbar = b - n;
795 if (bbar <= 0) {
796 --n;
797 bbar += 1;
798 }
799 fract = ibetaAStep(bbar, a, y, x, n, normalised);
800 fract += ibetaAStep(a, bbar, x, y, 20, normalised);
801 if (invert) {
802
803
804 fract -= 1;
805 }
806 fract = betaSmallBLargeASeries(a + 20, bbar, x, y, fract, 1, pol, normalised);
807 if (invert) {
808 fract = -fract;
809 invert = false;
810 }
811 } else {
812 fract = ibetaFraction2(a, b, x, y, pol, normalised);
813 }
814 } else {
815 fract = ibetaFraction2(a, b, x, y, pol, normalised);
816 }
817 }
818 if (invert) {
819 return (normalised ? 1 : beta(a, b)) - fract;
820 }
821 return fract;
822 }
823
824
825
826
827
828
829
830
831
832
833
834
835 private static double ibetaSeries(double a, double b, double x, double s0, boolean normalised, Policy pol) {
836 double result;
837
838 if (normalised) {
839 final double c = a + b;
840
841
842 final double agh = a + BoostGamma.Lanczos.GMH;
843 final double bgh = b + BoostGamma.Lanczos.GMH;
844 final double cgh = c + BoostGamma.Lanczos.GMH;
845 result = BoostGamma.Lanczos.lanczosSumExpGScaled(c) /
846 (BoostGamma.Lanczos.lanczosSumExpGScaled(a) * BoostGamma.Lanczos.lanczosSumExpGScaled(b));
847
848 final double l1 = Math.log(cgh / bgh) * (b - 0.5f);
849 final double l2 = Math.log(x * cgh / agh) * a;
850
851
852
853 if (l1 > LOG_MIN_VALUE && l1 < LOG_MAX_VALUE && l2 > LOG_MIN_VALUE && l2 < LOG_MAX_VALUE) {
854 if (a * b < bgh * 10) {
855 result *= Math.exp((b - 0.5f) * Math.log1p(a / bgh));
856 } else {
857 result *= Math.pow(cgh / bgh, b - 0.5f);
858 }
859 result *= Math.pow(x * cgh / agh, a);
860 result *= Math.sqrt(agh / Math.E);
861 } else {
862
863
864
865 result = Math.log(result) + l1 + l2 + (Math.log(agh) - 1) / 2;
866 result = Math.exp(result);
867 }
868 } else {
869
870 result = Math.pow(x, a);
871 }
872 double rescale = 1.0;
873 if (result < Double.MIN_NORMAL) {
874
875
876
877
878
879
880
881
882 if (s0 + result / a == s0) {
883 return s0;
884 }
885 s0 *= TWO_POW_53;
886 result *= TWO_POW_53;
887 rescale = TWO_POW_M53;
888 }
889
890 final double eps = pol.getEps();
891 final int maxIterations = pol.getMaxIterations();
892
893
894 final double result1 = result;
895 final DoubleSupplier gen = new DoubleSupplier() {
896
897 private double result = result1;
898
899 private final double poch = -b;
900
901 private int n;
902
903 @Override
904 public double getAsDouble() {
905 final double r = result / (a + n);
906 n++;
907 result *= (n + poch) * x / n;
908 return r;
909 }
910 };
911
912 return BoostTools.sumSeries(gen, eps, maxIterations, s0) * rescale;
913 }
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929 private static double risingFactorialRatio(double a, double b, int k) {
930
931
932
933
934
935
936
937
938 double result = 1;
939 for (int i = 0; i < k; ++i) {
940 result *= (a + i) / (b + i);
941 }
942 return result;
943 }
944
945
946
947
948
949
950
951
952
953
954
955
956 private static double binomialCCdf(int n, int k, double x, double y) {
957 double result = Math.pow(x, n);
958
959 if (result > Double.MIN_NORMAL) {
960 double term = result;
961 for (int i = n - 1; i > k; --i) {
962 term *= ((i + 1) * y) / ((n - i) * x);
963 result += term;
964 }
965 } else {
966
967
968 int start = (int) (n * x);
969 if (start <= k + 1) {
970 start = k + 2;
971 }
972
973
974 result = binomialTerm(n, start, x, y);
975 if (result == 0) {
976
977
978 for (int i = start - 1; i > k; --i) {
979 result += binomialTerm(n, i, x, y);
980 }
981 } else {
982 double term = result;
983 final double startTerm = result;
984 for (int i = start - 1; i > k; --i) {
985 term *= ((i + 1) * y) / ((n - i) * x);
986 result += term;
987 }
988 term = startTerm;
989 for (int i = start + 1; i <= n; ++i) {
990 term *= (n - i + 1) * x / (i * y);
991 result += term;
992 }
993 }
994 }
995
996 return result;
997 }
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013 private static double binomialTerm(int n, int k, double x, double y) {
1014
1015
1016
1017
1018 final double binom = binomialCoefficient(n, k);
1019 if (!Double.isFinite(binom)) {
1020
1021 return 0;
1022 }
1023
1024
1025
1026
1027 return binom * Math.pow(y, n - k) * Math.pow(x, k);
1028 }
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044 static double binomialCoefficient(int n, int k) {
1045
1046
1047 final int m = Math.min(k, n - k);
1048
1049
1050 if (m == 0) {
1051 return 1;
1052 }
1053 if (m == 1) {
1054 return n;
1055 }
1056 if (m == 2) {
1057 return 0.5 * n * (n - 1);
1058 }
1059 if (m == 3) {
1060
1061 return 0.5 * n * (n - 1) * (n - 2) / 3;
1062 }
1063
1064 double result;
1065 if (n <= MAX_FACTORIAL) {
1066
1067 result = BoostGamma.uncheckedFactorial(n);
1068
1069 result /= BoostGamma.uncheckedFactorial(m);
1070 result /= BoostGamma.uncheckedFactorial(n - m);
1071 } else {
1072
1073
1074
1075
1076
1077
1078
1079
1080 result = 1;
1081 for (int i = 1; i < m; i++) {
1082 result *= n - m + i;
1083 result /= i;
1084 }
1085
1086 if (result * n > Double.MAX_VALUE) {
1087 result /= m;
1088 result *= n;
1089 } else {
1090 result *= n;
1091 result /= m;
1092 }
1093 }
1094
1095 return Math.ceil(result - 0.5f);
1096 }
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109 private static double ibetaAStep(double a, double b, double x, double y, int k, boolean normalised) {
1110 double prefix = ibetaPowerTerms(a, b, x, y, normalised);
1111 prefix /= a;
1112 if (prefix == 0) {
1113 return prefix;
1114 }
1115 double sum = 1;
1116 double term = 1;
1117
1118 for (int i = 0; i < k - 1; ++i) {
1119 term *= (a + b + i) * x / (a + i + 1);
1120 sum += term;
1121 }
1122 prefix *= sum;
1123
1124 return prefix;
1125 }
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140 private static double betaSmallBLargeASeries(double a, double b, double x, double y, double s0, double mult,
1141 Policy pol, boolean normalised) {
1142
1143
1144
1145
1146
1147 final double bm1 = b - 1;
1148 final double t = a + bm1 / 2;
1149 final double lx;
1150 if (y < 0.35) {
1151 lx = Math.log1p(-y);
1152 } else {
1153 lx = Math.log(x);
1154 }
1155 final double u = -t * lx;
1156
1157 final double h = BoostGamma.regularisedGammaPrefix(b, u);
1158 if (h <= Double.MIN_NORMAL) {
1159
1160
1161
1162
1163 if (s0 == 0) {
1164 return ibetaFraction(a, b, x, y, pol, normalised);
1165 }
1166 return s0;
1167 }
1168 double prefix;
1169 if (normalised) {
1170 prefix = h / GammaRatio.delta(a, b);
1171 prefix /= Math.pow(t, b);
1172 } else {
1173 prefix = BoostGamma.fullIgammaPrefix(b, u) / Math.pow(t, b);
1174 }
1175 prefix *= mult;
1176
1177
1178
1179
1180
1181 final double[] p = new double[PN_SIZE];
1182
1183 p[0] = 1;
1184
1185
1186
1187 double j = BoostGamma.gammaQ(b, u, pol) / h;
1188
1189
1190
1191
1192 double sum = s0 + prefix * j;
1193
1194
1195 int tnp1 = 1;
1196 double lx2 = lx / 2;
1197 lx2 *= lx2;
1198 double lxp = 1;
1199 final double t4 = 4 * t * t;
1200 double b2n = b;
1201
1202 for (int n = 1; n < PN_SIZE; ++n) {
1203
1204
1205
1206 tnp1 += 2;
1207 p[n] = 0;
1208 int tmp1 = 3;
1209 for (int m = 1; m < n; ++m) {
1210 final double mbn = m * b - n;
1211 p[n] += mbn * p[n - m] / BoostGamma.uncheckedFactorial(tmp1);
1212 tmp1 += 2;
1213 }
1214 p[n] /= n;
1215 p[n] += bm1 / BoostGamma.uncheckedFactorial(tnp1);
1216
1217
1218
1219 j = (b2n * (b2n + 1) * j + (u + b2n + 1) * lxp) / t4;
1220 lxp *= lx2;
1221 b2n += 2;
1222
1223
1224
1225 final double r = prefix * p[n] * j;
1226 final double previous = sum;
1227 sum += r;
1228
1229
1230
1231
1232 if (sum == previous) {
1233 break;
1234 }
1235 }
1236 return sum;
1237 }
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256 static double ibetaFraction2(double a, double b, double x, double y, Policy pol, boolean normalised) {
1257 final double result = ibetaPowerTerms(a, b, x, y, normalised);
1258 if (result == 0) {
1259 return result;
1260 }
1261
1262 final double eps = pol.getEps();
1263 final int maxIterations = pol.getMaxIterations();
1264
1265 final Supplier<Coefficient> gen = new Supplier<Coefficient>() {
1266
1267 private int m;
1268
1269 @Override
1270 public Coefficient get() {
1271 double aN = (a + m - 1) * (a + b + m - 1) * m * (b - m) * x * x;
1272 final double denom = a + 2 * m - 1;
1273 aN /= denom * denom;
1274
1275 double bN = m;
1276 bN += (m * (b - m) * x) / (a + 2 * m - 1);
1277 bN += ((a + m) * (a * y - b * x + 1 + m * (2 - x))) / (a + 2 * m + 1);
1278
1279 ++m;
1280 return Coefficient.of(aN, bN);
1281 }
1282 };
1283
1284
1285 final double fract = GeneralizedContinuedFraction.value(gen, eps, maxIterations);
1286 return result / fract;
1287 }
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312 static double ibetaFraction(double a, double b, double x, double y, Policy pol, boolean normalised) {
1313 final double result = ibetaPowerTerms(a, b, x, y, normalised);
1314 if (result == 0) {
1315 return result;
1316 }
1317
1318 final double eps = pol.getEps();
1319 final int maxIterations = pol.getMaxIterations();
1320
1321 final Supplier<Coefficient> gen = new Supplier<Coefficient>() {
1322
1323 private int n;
1324
1325 @Override
1326 public Coefficient get() {
1327
1328
1329 final int m = n;
1330 final int k = m / 2;
1331 final double aN;
1332 if ((m & 0x1) == 0) {
1333
1334
1335 aN = (k * (b - k) * x) /
1336 ((a + m - 1) * (a + m));
1337 } else {
1338
1339
1340
1341 aN = -((a + k) * (a + b + k) * x) /
1342 ((a + m - 1) * (a + m));
1343 }
1344
1345 n = m + 1;
1346 return Coefficient.of(aN, 1);
1347 }
1348 };
1349
1350
1351 final double fract = GeneralizedContinuedFraction.value(gen, eps, maxIterations);
1352 return (result / a) / fract;
1353 }
1354 }