00001
00002
00003
00004
00005
00006
00007
00008 #include "Math/Error.h"
00009
00010 #include "SpecFuncCephes.h"
00011
00012 #include <cmath>
00013
00014 #include <limits>
00015
00016 namespace ROOT {
00017 namespace Math {
00018
00019 namespace Cephes {
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076 static double s2pi = 2.50662827463100050242E0;
00077
00078 static double P0[5] = {
00079 -5.99633501014107895267E1,
00080 9.80010754185999661536E1,
00081 -5.66762857469070293439E1,
00082 1.39312609387279679503E1,
00083 -1.23916583867381258016E0,
00084 };
00085 static double Q0[8] = {
00086 1.95448858338141759834E0,
00087 4.67627912898881538453E0,
00088 8.63602421390890590575E1,
00089 -2.25462687854119370527E2,
00090 2.00260212380060660359E2,
00091 -8.20372256168333339912E1,
00092 1.59056225126211695515E1,
00093 -1.18331621121330003142E0,
00094 };
00095 static double P1[9] = {
00096 4.05544892305962419923E0,
00097 3.15251094599893866154E1,
00098 5.71628192246421288162E1,
00099 4.40805073893200834700E1,
00100 1.46849561928858024014E1,
00101 2.18663306850790267539E0,
00102 -1.40256079171354495875E-1,
00103 -3.50424626827848203418E-2,
00104 -8.57456785154685413611E-4,
00105 };
00106 static double Q1[8] = {
00107 1.57799883256466749731E1,
00108 4.53907635128879210584E1,
00109 4.13172038254672030440E1,
00110 1.50425385692907503408E1,
00111 2.50464946208309415979E0,
00112 -1.42182922854787788574E-1,
00113 -3.80806407691578277194E-2,
00114 -9.33259480895457427372E-4,
00115 };
00116 static double P2[9] = {
00117 3.23774891776946035970E0,
00118 6.91522889068984211695E0,
00119 3.93881025292474443415E0,
00120 1.33303460815807542389E0,
00121 2.01485389549179081538E-1,
00122 1.23716634817820021358E-2,
00123 3.01581553508235416007E-4,
00124 2.65806974686737550832E-6,
00125 6.23974539184983293730E-9,
00126 };
00127 static double Q2[8] = {
00128 6.02427039364742014255E0,
00129 3.67983563856160859403E0,
00130 1.37702099489081330271E0,
00131 2.16236993594496635890E-1,
00132 1.34204006088543189037E-2,
00133 3.28014464682127739104E-4,
00134 2.89247864745380683936E-6,
00135 6.79019408009981274425E-9,
00136 };
00137 double ndtri( double y0 )
00138 {
00139 double x, y, z, y2, x0, x1;
00140 int code;
00141 if( y0 <= 0.0 )
00142 return( - std::numeric_limits<double>::infinity() );
00143 if( y0 >= 1.0 )
00144 return( + std::numeric_limits<double>::infinity() );
00145 code = 1;
00146 y = y0;
00147 if( y > (1.0 - 0.13533528323661269189) )
00148 {
00149 y = 1.0 - y;
00150 code = 0;
00151 }
00152 if( y > 0.13533528323661269189 )
00153 {
00154 y = y - 0.5;
00155 y2 = y * y;
00156 x = y + y * (y2 * Polynomialeval( y2, P0, 4)/ Polynomial1eval( y2, Q0, 8 ));
00157 x = x * s2pi;
00158 return(x);
00159 }
00160 x = std::sqrt( -2.0 * std::log(y) );
00161 x0 = x - std::log(x)/x;
00162 z = 1.0/x;
00163 if( x < 8.0 )
00164 x1 = z * Polynomialeval( z, P1, 8 )/ Polynomial1eval ( z, Q1, 8 );
00165 else
00166 x1 = z * Polynomialeval( z, P2, 8 )/ Polynomial1eval( z, Q2, 8 );
00167 x = x0 - x1;
00168 if( code != 0 )
00169 x = -x;
00170 return( x );
00171 }
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225 double igami( double a, double y0 )
00226 {
00227 double x0, x1, x, yl, yh, y, d, lgm, dithresh;
00228 int i, dir;
00229
00230
00231 if (a<= 0) {
00232 MATH_ERROR_MSG("Cephes::igami","Wrong domain for parameter a (must be > 0)");
00233 return 0;
00234 }
00235 if (y0 <= 0) {
00236
00237 return std::numeric_limits<double>::infinity();
00238 }
00239 if (y0 >= 1) {
00240
00241 return 0;
00242 }
00243
00244
00245
00246 static double kMAXNUM = std::numeric_limits<double>::max();
00247 x0 = kMAXNUM;
00248 yl = 0;
00249 x1 = 0;
00250 yh = 1.0;
00251 dithresh = 5.0 * kMACHEP;
00252
00253
00254 d = 1.0/(9.0*a);
00255 y = ( 1.0 - d - ndtri(y0) * std::sqrt(d) );
00256 x = a * y * y * y;
00257
00258 lgm = lgam(a);
00259
00260 for( i=0; i<10; i++ )
00261 {
00262 if( x > x0 || x < x1 )
00263 goto ihalve;
00264 y = igamc(a,x);
00265 if( y < yl || y > yh )
00266 goto ihalve;
00267 if( y < y0 )
00268 {
00269 x0 = x;
00270 yl = y;
00271 }
00272 else
00273 {
00274 x1 = x;
00275 yh = y;
00276 }
00277
00278 d = (a - 1.0) * std::log(x) - x - lgm;
00279 if( d < -kMAXLOG )
00280 goto ihalve;
00281 d = -std::exp(d);
00282
00283 d = (y - y0)/d;
00284 if( std::fabs(d/x) < kMACHEP )
00285 goto done;
00286 x = x - d;
00287 }
00288
00289
00290 ihalve:
00291
00292 d = 0.0625;
00293 if( x0 == kMAXNUM )
00294 {
00295 if( x <= 0.0 )
00296 x = 1.0;
00297 while( x0 == kMAXNUM )
00298 {
00299 x = (1.0 + d) * x;
00300 y = igamc( a, x );
00301 if( y < y0 )
00302 {
00303 x0 = x;
00304 yl = y;
00305 break;
00306 }
00307 d = d + d;
00308 }
00309 }
00310 d = 0.5;
00311 dir = 0;
00312
00313 for( i=0; i<400; i++ )
00314 {
00315 x = x1 + d * (x0 - x1);
00316 y = igamc( a, x );
00317 lgm = (x0 - x1)/(x1 + x0);
00318 if( std::fabs(lgm) < dithresh )
00319 break;
00320 lgm = (y - y0)/y0;
00321 if( std::fabs(lgm) < dithresh )
00322 break;
00323 if( x <= 0.0 )
00324 break;
00325 if( y >= y0 )
00326 {
00327 x1 = x;
00328 yh = y;
00329 if( dir < 0 )
00330 {
00331 dir = 0;
00332 d = 0.5;
00333 }
00334 else if( dir > 1 )
00335 d = 0.5 * d + 0.5;
00336 else
00337 d = (y0 - yl)/(yh - yl);
00338 dir += 1;
00339 }
00340 else
00341 {
00342 x0 = x;
00343 yl = y;
00344 if( dir > 0 )
00345 {
00346 dir = 0;
00347 d = 0.5;
00348 }
00349 else if( dir < -1 )
00350 d = 0.5 * d;
00351 else
00352 d = (y0 - yl)/(yh - yl);
00353 dir -= 1;
00354 }
00355 }
00356
00357
00358
00359
00360 done:
00361 return( x );
00362 }
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411 double incbi( double aa, double bb, double yy0 )
00412 {
00413 double a, b, y0, d, y, x, x0, x1, lgm, yp, di, dithresh, yl, yh, xt;
00414 int i, rflg, dir, nflg;
00415
00416
00417 if (aa<= 0) {
00418 MATH_ERROR_MSG("Cephes::incbi","Wrong domain for parameter a (must be > 0)");
00419 return 0;
00420 }
00421 if (bb<= 0) {
00422 MATH_ERROR_MSG("Cephes::incbi","Wrong domain for parameter b (must be > 0)");
00423 return 0;
00424 }
00425
00426
00427 i = 0;
00428 if( yy0 <= 0 )
00429 return(0.0);
00430 if( yy0 >= 1.0 )
00431 return(1.0);
00432 x0 = 0.0;
00433 yl = 0.0;
00434 x1 = 1.0;
00435 yh = 1.0;
00436 nflg = 0;
00437
00438 if( aa <= 1.0 || bb <= 1.0 )
00439 {
00440 dithresh = 1.0e-6;
00441 rflg = 0;
00442 a = aa;
00443 b = bb;
00444 y0 = yy0;
00445 x = a/(a+b);
00446 y = incbet( a, b, x );
00447 goto ihalve;
00448 }
00449 else
00450 {
00451 dithresh = 1.0e-4;
00452 }
00453
00454
00455 yp = -ndtri(yy0);
00456
00457 if( yy0 > 0.5 )
00458 {
00459 rflg = 1;
00460 a = bb;
00461 b = aa;
00462 y0 = 1.0 - yy0;
00463 yp = -yp;
00464 }
00465 else
00466 {
00467 rflg = 0;
00468 a = aa;
00469 b = bb;
00470 y0 = yy0;
00471 }
00472
00473 lgm = (yp * yp - 3.0)/6.0;
00474 x = 2.0/( 1.0/(2.0*a-1.0) + 1.0/(2.0*b-1.0) );
00475 d = yp * std::sqrt( x + lgm ) / x
00476 - ( 1.0/(2.0*b-1.0) - 1.0/(2.0*a-1.0) )
00477 * (lgm + 5.0/6.0 - 2.0/(3.0*x));
00478 d = 2.0 * d;
00479 if( d < kMINLOG )
00480 {
00481 x = 1.0;
00482 goto under;
00483 }
00484 x = a/( a + b * std::exp(d) );
00485 y = incbet( a, b, x );
00486 yp = (y - y0)/y0;
00487 if( std::fabs(yp) < 0.2 )
00488 goto newt;
00489
00490
00491 ihalve:
00492
00493 dir = 0;
00494 di = 0.5;
00495 for( i=0; i<100; i++ )
00496 {
00497 if( i != 0 )
00498 {
00499 x = x0 + di * (x1 - x0);
00500 if( x == 1.0 )
00501 x = 1.0 - kMACHEP;
00502 if( x == 0.0 )
00503 {
00504 di = 0.5;
00505 x = x0 + di * (x1 - x0);
00506 if( x == 0.0 )
00507 goto under;
00508 }
00509 y = incbet( a, b, x );
00510 yp = (x1 - x0)/(x1 + x0);
00511 if( std::fabs(yp) < dithresh )
00512 goto newt;
00513 yp = (y-y0)/y0;
00514 if( std::fabs(yp) < dithresh )
00515 goto newt;
00516 }
00517 if( y < y0 )
00518 {
00519 x0 = x;
00520 yl = y;
00521 if( dir < 0 )
00522 {
00523 dir = 0;
00524 di = 0.5;
00525 }
00526 else if( dir > 3 )
00527 di = 1.0 - (1.0 - di) * (1.0 - di);
00528 else if( dir > 1 )
00529 di = 0.5 * di + 0.5;
00530 else
00531 di = (y0 - y)/(yh - yl);
00532 dir += 1;
00533 if( x0 > 0.75 )
00534 {
00535 if( rflg == 1 )
00536 {
00537 rflg = 0;
00538 a = aa;
00539 b = bb;
00540 y0 = yy0;
00541 }
00542 else
00543 {
00544 rflg = 1;
00545 a = bb;
00546 b = aa;
00547 y0 = 1.0 - yy0;
00548 }
00549 x = 1.0 - x;
00550 y = incbet( a, b, x );
00551 x0 = 0.0;
00552 yl = 0.0;
00553 x1 = 1.0;
00554 yh = 1.0;
00555 goto ihalve;
00556 }
00557 }
00558 else
00559 {
00560 x1 = x;
00561 if( rflg == 1 && x1 < kMACHEP )
00562 {
00563 x = 0.0;
00564 goto done;
00565 }
00566 yh = y;
00567 if( dir > 0 )
00568 {
00569 dir = 0;
00570 di = 0.5;
00571 }
00572 else if( dir < -3 )
00573 di = di * di;
00574 else if( dir < -1 )
00575 di = 0.5 * di;
00576 else
00577 di = (y - y0)/(yh - yl);
00578 dir -= 1;
00579 }
00580 }
00581
00582 if( x0 >= 1.0 )
00583 {
00584 x = 1.0 - kMACHEP;
00585 goto done;
00586 }
00587 if( x <= 0.0 )
00588 {
00589 under:
00590
00591 x = 0.0;
00592 goto done;
00593 }
00594
00595 newt:
00596
00597 if( nflg )
00598 goto done;
00599 nflg = 1;
00600 lgm = lgam(a+b) - lgam(a) - lgam(b);
00601
00602 for( i=0; i<8; i++ )
00603 {
00604
00605 if( i != 0 )
00606 y = incbet(a,b,x);
00607 if( y < yl )
00608 {
00609 x = x0;
00610 y = yl;
00611 }
00612 else if( y > yh )
00613 {
00614 x = x1;
00615 y = yh;
00616 }
00617 else if( y < y0 )
00618 {
00619 x0 = x;
00620 yl = y;
00621 }
00622 else
00623 {
00624 x1 = x;
00625 yh = y;
00626 }
00627 if( x == 1.0 || x == 0.0 )
00628 break;
00629
00630 d = (a - 1.0) * std::log(x) + (b - 1.0) * std::log(1.0-x) + lgm;
00631 if( d < kMINLOG )
00632 goto done;
00633 if( d > kMAXLOG )
00634 break;
00635 d = std::exp(d);
00636
00637 d = (y - y0)/d;
00638 xt = x - d;
00639 if( xt <= x0 )
00640 {
00641 y = (x - x0) / (x1 - x0);
00642 xt = x0 + 0.5 * y * (x - x0);
00643 if( xt <= 0.0 )
00644 break;
00645 }
00646 if( xt >= x1 )
00647 {
00648 y = (x1 - x) / (x1 - x0);
00649 xt = x1 - 0.5 * y * (x1 - x);
00650 if( xt >= 1.0 )
00651 break;
00652 }
00653 x = xt;
00654 if( std::fabs(d/x) < 128.0 * kMACHEP )
00655 goto done;
00656 }
00657
00658 dithresh = 256.0 * kMACHEP;
00659 goto ihalve;
00660
00661 done:
00662
00663 if( rflg )
00664 {
00665 if( x <= kMACHEP )
00666 x = 1.0 - kMACHEP;
00667 else
00668 x = 1.0 - x;
00669 }
00670 return( x );
00671 }
00672
00673 }
00674
00675 }
00676 }