1 module rmathd.common; 2 3 public import std.math: sin, cos, tan, atan, sqrt, exp, expm1, log, isNaN, isFinite, ldexp, nearbyint, floor, 4 round, abs, fabs, fmod, trunc, log1p, pow, ceil; 5 public import core.stdc.math: lgammaf, lgammal; 6 public import core.stdc.float_ : FLT_MIN_EXP, FLT_MANT_DIG, LDBL_MIN_EXP, DBL_MIN_EXP, DBL_MANT_DIG, LDBL_MANT_DIG, 7 FLT_MIN, DBL_MIN, LDBL_MIN, FLT_MAX, DBL_MAX, LDBL_MAX, FLT_EPSILON, DBL_EPSILON, 8 LDBL_EPSILON, FLT_MAX_EXP, DBL_MAX_EXP, LDBL_MAX_EXP, FLT_RADIX; 9 10 enum M_PI = 3.141592653589793238462643383280; 11 enum M_LN2 = 0.693147180559945309417232121458; 12 enum M_2PI = 6.283185307179586476925286766559; 13 enum M_LN10 = 2.302585092994045684017991454684; 14 enum M_1_PI = 0.318309886183790671537767526745; 15 enum M_PI_2 = 1.570796326794896619231321691640; 16 enum M_SQRT2 = 1.414213562373095048801688724210; 17 enum M_LN_2PI = 1.837877066409345483560659472811; 18 enum M_LOG10_2 = 0.301029995663981195213738894724; 19 enum M_SQRT_32 = 5.656854249492380195206754896838; 20 enum M_SQRT_PI = 1.772453850905516027298167483341; 21 enum M_SQRT_2dPI = 0.797884560802865355879892119869; 22 enum M_1_SQRT_2PI = 0.398942280401432677939946059934; 23 enum M_LN_SQRT_PI = 0.572364942924700087071713675677; 24 enum M_LN_SQRT_2PI = 0.918938533204672741780329736406; 25 enum M_LN_SQRT_PId2 = 0.225791352644727432363097614947; 26 enum CHAR_BIT = 8; 27 enum INT_MAX = int.max; 28 29 enum N01type { 30 BUGGY_KINDERMAN_RAMAGE, 31 AHRENS_DIETER, 32 BOX_MULLER, 33 USER_NORM, 34 INVERSION, 35 KINDERMAN_RAMAGE 36 } 37 38 enum BUGGY_KINDERMAN_RAMAGE = N01type.BUGGY_KINDERMAN_RAMAGE; 39 enum AHRENS_DIETER = N01type.AHRENS_DIETER; 40 enum BOX_MULLER = N01type.BOX_MULLER; 41 enum USER_NORM = N01type.USER_NORM; 42 enum INVERSION = N01type.INVERSION; 43 enum KINDERMAN_RAMAGE = N01type.KINDERMAN_RAMAGE; 44 45 void doNothing(){}; 46 47 T fmax2(T)(T x, T y) 48 { 49 if (isNaN(x) || isNaN(y)) 50 return x + y; 51 return (x < y) ? y : x; 52 } 53 54 T max(T)(T x, T y) 55 { 56 return (x < y) ? y : x; 57 } 58 59 alias imax2 = max; 60 61 T min(T)(T x, T y) 62 { 63 return (x < y) ? x : y; 64 } 65 alias imin2 = min; 66 67 T fmin2(T)(T x, T y) 68 { 69 if (isNaN(x) || isNaN(y)) 70 return x + y; 71 return (x < y) ? x : y; 72 } 73 74 T fsign(T)(T x, T y) 75 { 76 if (isNaN(x) || isNaN(y)) 77 return x + y; 78 return ((y >= 0) ? fabs(x) : -fabs(x)); 79 } 80 81 /* lgamma float, double, real */ 82 T lgamma(T: float)(T x) 83 { 84 return lgammaf(x); 85 } 86 87 T lgamma(T: double)(T x) 88 { 89 import core.stdc.math: lgamma; 90 return lgamma(x); 91 } 92 93 T lgamma(T: real)(T x) 94 { 95 return lgammal(x); 96 } 97 98 99 template SQR(T) 100 { 101 auto SQR(T x) 102 { 103 return x*x; 104 } 105 } 106 107 enum scalefactor = SQR(SQR(SQR(4294967296.0))); 108 109 template R_Log1_Exp(T) 110 { 111 auto R_Log1_Exp(T x) 112 { 113 return (x > -M_LN2 ? log(-expm1(x)) : log1p(-exp(x))); 114 } 115 } 116 117 template R_DT_Log(T) 118 { 119 auto R_DT_Log(T p, int lower_tail) 120 { 121 return (lower_tail? p : R_Log1_Exp!T(p)); 122 } 123 } 124 125 template R_D_exp(T) 126 { 127 auto R_D_exp(T x, int log_p) 128 { 129 return (log_p ? x : exp(x)); 130 } 131 } 132 133 template R_D_log(T) 134 { 135 auto R_D_log(T p, int log_p) 136 { 137 return (log_p ? p : log(p)); 138 } 139 } 140 141 template R_D_fexp(T) 142 { 143 auto R_D_fexp(T f, T x, int give_log) 144 { 145 return (give_log ? -0.5*log(f) + x : exp(x)/sqrt(f)); 146 } 147 } 148 149 template MIN_EXP(T) 150 { 151 static if(is(T : double)) 152 enum MIN_EXP = DBL_MIN_EXP; 153 else static if(is(T : real)) 154 enum MIN_EXP = LDBL_MIN_EXP; 155 else 156 enum MIN_EXP = FLT_MIN_EXP; 157 } 158 159 template MANT_DIG(T) 160 { 161 static if(is(T : double)) 162 enum MANT_DIG = DBL_MANT_DIG; 163 else static if(is(T : real)) 164 enum MANT_DIG = LDBL_MANT_DIG; 165 else 166 enum MANT_DIG = FLT_MANT_DIG; 167 } 168 169 template MIN(T) 170 { 171 static if(is(T : double)) 172 enum MIN = DBL_MIN; 173 else static if(is(T : real)) 174 enum MIN = LDBL_MIN; 175 else 176 enum MIN = FLT_MIN; 177 } 178 179 template MAX(T) 180 { 181 static if(is(T : double)) 182 enum MAX = DBL_MAX; 183 else static if(is(T : real)) 184 enum MAX = LDBL_MAX; 185 else 186 enum MAX = FLT_MAX; 187 } 188 189 template EPSILON(T) 190 { 191 static if(is(T : double)) 192 enum EPSILON = DBL_EPSILON; 193 else static if(is(T : real)) 194 enum EPSILON = LDBL_EPSILON; 195 else 196 enum EPSILON = FLT_EPSILON; 197 } 198 199 template MAX_EXP(T) 200 { 201 static if(is(T : double)) 202 enum MAX_EXP = DBL_MAX_EXP; 203 else static if(is(T : real)) 204 enum MAX_EXP = LDBL_MAX_EXP; 205 else 206 enum MAX_EXP = FLT_MAX_EXP; 207 } 208 209 //static const double M_cutoff = M_LN2 * MAX_EXP!T/EPSILON!T;/*=3.196577e18*/ 210 211 mixin template M_cutoff(T) 212 { 213 static const(T) M_cutoff = M_LN2 * MAX_EXP!T/EPSILON!T; 214 } 215 216 217 218 mixin template R_D__0(alias log_p) 219 { 220 T R_D__0 = (log_p ? -T.infinity : 0.); 221 } 222 223 224 mixin template R_D__1(alias log_p) 225 { 226 T R_D__1 = (log_p ? 0. : 1.); 227 } 228 229 template R_D_val(T) 230 { 231 auto R_D_val (T x, int log_p) 232 { 233 return (log_p ? log(x) : x); 234 } 235 } 236 237 template R_D_Clog(T) 238 { 239 auto R_D_Clog(T p, int log_p) 240 { 241 return (log_p ? log1p(-p) : (0.5 - p + 0.5)); 242 } 243 } 244 245 template R_DT_val(T) 246 { 247 auto R_DT_val(T x, int lower_tail, int log_p) 248 { 249 return (lower_tail ? R_D_val!T(x, log_p) : R_D_Clog!T(x, log_p)); 250 } 251 } 252 253 template R_D_qIv(T) 254 { 255 auto R_D_qIv(T p, int log_p) 256 { 257 return (log_p ? exp(p) : p); 258 } 259 } 260 261 template R_DT_0(T) 262 { 263 auto R_DT_0(int lower_tail, int log_p) 264 { 265 mixin R_D__0!log_p; 266 mixin R_D__1!log_p; 267 return (lower_tail ? R_D__0 : R_D__1); 268 } 269 } 270 271 272 /* 273 template R_DT_0(alias lower_tail, alias log_p) 274 { 275 mixin R_D__0!log_p; 276 mixin R_D__1!log_p; 277 T R_DT_0 = (lower_tail ? R_D__0 : R_D__1); 278 } 279 */ 280 281 282 template R_DT_1(T) 283 { 284 auto R_DT_1(int lower_tail, int log_p) 285 { 286 mixin R_D__0!log_p; 287 mixin R_D__1!log_p; 288 return (lower_tail ? R_D__1 : R_D__0); 289 } 290 } 291 292 293 auto R_D_half(int log_p){ 294 return (log_p ? -M_LN2 : 0.5); 295 } 296 297 298 /* 299 template R_DT_1(alias lower_tail, alias log_p) 300 { 301 mixin R_D__0!log_p; 302 mixin R_D__1!log_p; 303 T R_DT_1 = (lower_tail ? R_D__1 : R_D__0); 304 } 305 */ 306 307 /* Mixin technique! */ 308 309 /* 310 mixin template R_D_Lval(alias p) 311 { 312 T R_D_Lval = (lower_tail ? (p) : (0.5 - p + 0.5)); 313 } 314 315 mixin template R_DT_qIv(alias p) 316 { 317 mixin R_D_Lval!(p); 318 T R_DT_qIv = (log_p ? (lower_tail ? exp(p) : - expm1(p)) : R_D_Lval); 319 } 320 */ 321 322 template R_D_Lval(T) 323 { 324 auto R_D_Lval(T p, int lower_tail) 325 { 326 return (lower_tail ? p : (0.5 - p + 0.5)); 327 } 328 } 329 330 mixin template R_DT_qIv(alias p) 331 { 332 T R_DT_qIv = (log_p ? (lower_tail ? exp(p) : - expm1(p)) : R_D_Lval!T(p, lower_tail)); 333 } 334 335 336 mixin template R_D_Cval(alias p) 337 { 338 T R_D_Cval = (lower_tail ? (0.5 - p + 0.5) : p); 339 } 340 341 mixin template R_DT_CIv(alias p) 342 { 343 mixin R_D_Cval!(p); 344 T R_DT_CIv = (log_p ? (lower_tail ? -expm1(p) : exp(p)) : R_D_Cval); 345 } 346 347 template R_Q_P01_boundaries(alias p, alias LEFT, alias RIGHT) 348 { 349 immutable(string) R_Q_P01_boundaries(){ 350 return `if (log_p) { 351 if(p > 0) 352 return T.nan; 353 if(p == 0) /* upper bound*/ 354 return lower_tail ? ` ~ RIGHT.stringof ~ ` : ` ~ LEFT.stringof ~ `; 355 if(p == -T.infinity) 356 return lower_tail ? `~ LEFT.stringof ~ ` : ` ~ RIGHT.stringof ~ `; 357 } else { /* !log_p */ 358 if(p < 0 || p > 1) 359 return T.nan; 360 if(p == 0) 361 return lower_tail ? ` ~ LEFT.stringof ~ ` : ` ~ RIGHT.stringof ~ `; 362 if(p == 1) 363 return lower_tail ? ` ~ RIGHT.stringof ~ ` : ` ~ LEFT.stringof ~ `; 364 }`; 365 } 366 } 367 368 template R_Q_P01_check(alias p) 369 { 370 immutable(string) R_Q_P01_check(){ 371 return `if ((log_p && ` ~ p.stringof ~ ` > 0) || (!log_p && (` ~ p.stringof ~ ` < 0 || ` ~ p.stringof ~ ` > 1))) 372 return T.nan;`; 373 } 374 } 375 376 template R_P_bounds_01(alias x, alias x_min, alias x_max) 377 { 378 immutable(string) R_P_bounds_01(){ 379 return `if(` ~ x.stringof ~ ` <= ` ~ x_min.stringof ~ `) return R_DT_0!T(lower_tail, log_p); 380 if(` ~ x.stringof ~ ` >= ` ~ x_max.stringof ~ `) return R_DT_1!T(lower_tail, log_p);`; 381 } 382 } 383 384 /* is typically not quite optimal for (-Inf,Inf) where 385 * you'd rather have */ 386 template R_P_bounds_Inf_01(alias x) 387 { 388 immutable(string) R_P_bounds_Inf_01(){ 389 return `if(!isFinite(` ~ x.stringof ~ `)) { 390 if (` ~ x.stringof ~ ` > 0) return R_DT_1!T(lower_tail, log_p); 391 return R_DT_0!T(lower_tail, log_p); 392 }`; 393 } 394 } 395 396 397 template R_D_LExp(T) 398 { 399 auto R_D_LExp(T x, int log_p) 400 { 401 return (log_p ? R_Log1_Exp!T(x) : log1p(-x)); 402 } 403 } 404 405 template R_DT_Clog(T) 406 { 407 auto R_DT_Clog(T p, int lower_tail, int log_p) 408 { 409 return (lower_tail? R_D_LExp!T(p, log_p): R_D_log!T(p, lower_tail)); /* log(1-p) in qF*/ 410 } 411 } 412 413 414 template R_DT_log(T) 415 { 416 auto R_DT_log(T p, int lower_tail) 417 { 418 return (lower_tail? R_D_log!T(p, lower_tail) : R_D_LExp!T(p, lower_tail)); 419 } 420 } 421 422 auto R_pow_di(T)(T x, int n) 423 { 424 T pow_ = 1.0; 425 426 if (isNaN(x)) return x; 427 if (n != 0) { 428 if (!isFinite(x)) 429 return pow(x, cast(T)n); 430 if (n < 0) { 431 n = -n; x = 1/x; 432 } 433 for(;;) { 434 if(n & 01) 435 pow_ *= x; 436 if(n >>= 1) 437 x *= x; 438 else 439 break; 440 } 441 } 442 return pow_; 443 } 444 445 446 template R_nonint(T){ 447 auto R_nonint(T x){ 448 return (fabs(x - nearbyint(x)) > 1e-7*fmax2!T(1., fabs(x))); 449 } 450 } 451 452 453 template R_D_negInonint(T) 454 { 455 auto R_D_negInonint(T x) 456 { 457 return (x < 0. || R_nonint!T(x)); 458 } 459 } 460 461 /* 462 template R_D_Lval(T) 463 { 464 auto R_D_Lval(T p, T lower_tail){ 465 return (lower_tail ? p : (0.5 - p + 0.5)); 466 } 467 } 468 */ 469 470 /* 471 template R_DT_qIv(T) 472 { 473 auto R_DT_qIv(T p, T log_p, T lower_tail){ 474 return (log_p ? (lower_tail ? exp(p) : - expm1(p)) : R_D_Lval!T(p, lower_tail)); 475 } 476 } 477 */ 478 479 template R_D_nonint_check(alias x){ 480 enum R_D_nonint_check = `if(R_nonint(` ~ x.stringof ~ `)) { 481 return R_D__0; 482 }`; 483 } 484 485 int chebyshev_init(T)(T* dos, int nos, T eta) 486 { 487 int i, ii; 488 T err; 489 490 if (nos < 1) 491 return 0; 492 493 err = 0.0; 494 i = 0; /* just to avoid compiler warnings */ 495 for (ii = 1; ii <= nos; ii++) { 496 i = nos - ii; 497 err += fabs(dos[i]); 498 if (err > eta) { 499 return i; 500 } 501 } 502 return i; 503 } 504 505 T chebyshev_eval(T)(T x, const(T)* a, const(int) n) 506 { 507 T b0, b1, b2, twox; 508 int i; 509 510 if (n < 1 || n > 1000) 511 return T.nan; 512 513 if (x < -1.1 || x > 1.1) 514 return T.nan; 515 516 twox = x * 2; 517 b2 = b1 = 0; 518 b0 = 0; 519 for (i = 1; i <= n; i++) { 520 b2 = b1; 521 b1 = b0; 522 b0 = twox * b1 - b2 + a[n - i]; 523 } 524 return (b0 - b2) * 0.5; 525 } 526 527 T d1mach(T)(int i) 528 { 529 switch(i) { 530 case 1: return MIN!T; 531 case 2: return MAX!T; 532 533 case 3: /* = FLT_RADIX ^ - DBL_MANT_DIG 534 for IEEE: = 2^-53 = 1.110223e-16 = .5*DBL_EPSILON */ 535 return 0.5*EPSILON!T; 536 537 case 4: /* = FLT_RADIX ^ (1- DBL_MANT_DIG) = 538 for IEEE: = 2^-52 = DBL_EPSILON */ 539 return EPSILON!T; 540 541 case 5: return M_LOG10_2; 542 543 default: return 0.0; 544 } 545 } 546 547 int i1mach(int i) 548 { 549 switch(i) { 550 551 case 1: return 5; 552 case 2: return 6; 553 case 3: return 0; 554 case 4: return 0; 555 556 case 5: return CHAR_BIT*int.sizeof; 557 case 6: return int.sizeof/char.sizeof; 558 559 case 7: return 2; 560 case 8: return CHAR_BIT*int.sizeof - 1; 561 case 9: return INT_MAX; 562 563 case 10: return FLT_RADIX; 564 565 case 11: return FLT_MANT_DIG; 566 case 12: return FLT_MIN_EXP; 567 case 13: return FLT_MAX_EXP; 568 569 case 14: return DBL_MANT_DIG; 570 case 15: return DBL_MIN_EXP; 571 case 16: return DBL_MAX_EXP; 572 573 default: return 0; 574 } 575 } 576 577 578 void gammalims(T)(T* xmin, T* xmax) 579 { 580 /* FIXME: Even better: If IEEE, #define these in nmath.h 581 and don't call gammalims() at all 582 */ 583 584 *xmin = -170.5674972726612; 585 *xmax = 171.61447887182298;/*(3 Intel/Sparc architectures)*/ 586 587 double alnbig, alnsml, xln, xold; 588 int i; 589 590 alnsml = log(d1mach!T(1)); 591 *xmin = -alnsml; 592 for (i = 1; i <= 10; ++i) { 593 xold = *xmin; 594 xln = log(*xmin); 595 *xmin -= *xmin * ((*xmin + .5) * xln - *xmin - .2258 + alnsml) / 596 (*xmin * xln + .5); 597 if (fabs(*xmin - xold) < .005) { 598 *xmin = -(*xmin) + .01; 599 goto find_xmax; 600 } 601 } 602 603 /* unable to find xmin */ 604 605 //ML_ERROR(ME_NOCONV, "gammalims"); 606 *xmin = *xmax = T.nan; 607 608 find_xmax: 609 610 alnbig = log(d1mach!T(2)); 611 *xmax = alnbig; 612 for (i = 1; i <= 10; ++i) { 613 xold = *xmax; 614 xln = log(*xmax); 615 *xmax -= *xmax * ((*xmax - .5) * xln - *xmax + .9189 - alnbig) / 616 (*xmax * xln - .5); 617 if (fabs(*xmax - xold) < .005) { 618 *xmax += -.01; 619 goto done; 620 } 621 } 622 623 /* unable to find xmax */ 624 625 //ML_ERROR(ME_NOCONV, "gammalims"); 626 *xmin = *xmax = T.nan; 627 628 done: 629 *xmin = fmax2(*xmin, -(*xmax) + 1); 630 } 631 632 T lgammacor(T)(T x) 633 { 634 const static T[15] algmcs = [ 635 +.1666389480451863247205729650822e+0, 636 -.1384948176067563840732986059135e-4, 637 +.9810825646924729426157171547487e-8, 638 -.1809129475572494194263306266719e-10, 639 +.6221098041892605227126015543416e-13, 640 -.3399615005417721944303330599666e-15, 641 +.2683181998482698748957538846666e-17, 642 -.2868042435334643284144622399999e-19, 643 +.3962837061046434803679306666666e-21, 644 -.6831888753985766870111999999999e-23, 645 +.1429227355942498147573333333333e-24, 646 -.3547598158101070547199999999999e-26, 647 +.1025680058010470912000000000000e-27, 648 -.3401102254316748799999999999999e-29, 649 +.1276642195630062933333333333333e-30 650 ]; 651 652 T tmp; 653 654 /* For IEEE double precision DBL_EPSILON = 2^-52 = 2.220446049250313e-16 : 655 * xbig = 2 ^ 26.5 656 * xmax = DBL_MAX / 48 = 2^1020 / 3 */ 657 const(int) nalgm = 5; 658 const(T) xbig = 94906265.62425156; 659 const(T) xmax = 3.745194030963158e306; 660 661 if (x < 10) 662 return T.nan; 663 else if (x >= xmax) { 664 //ML_ERROR(ME_UNDERFLOW, "lgammacor"); 665 /* allow to underflow below */ 666 } 667 else if (x < xbig) { 668 tmp = 10 / x; 669 return chebyshev_eval!T(tmp * tmp * 2 - 1, algmcs.ptr, nalgm) / x; 670 } 671 return 1 / (x * 12); 672 } 673 674 /* Start of trig pi functions */ 675 676 // cos(pi * x) -- exact when x = k/2 for all integer k 677 T cospi(T: double)(T x) { 678 if (isNaN(x)) 679 return x; 680 if(!isFinite(x)) 681 return T.nan; 682 683 x = fmod(fabs(x), 2.);// cos() symmetric; cos(pi(x + 2k)) == cos(pi x) for all integer k 684 if(fmod(x, 1.) == 0.5) 685 return 0.; 686 if(x == 1.) 687 return -1.; 688 if(x == 0.) 689 return 1.; 690 // otherwise 691 return cos(M_PI * x); 692 } 693 694 // sin(pi * x) -- exact when x = k/2 for all integer k 695 T sinpi(T: double)(T x) { 696 if (isNaN(x)) return x; 697 if(!isFinite(x)) 698 return T.nan; 699 700 x = fmod(x, 2.); // sin(pi(x + 2k)) == sin(pi x) for all integer k 701 // map (-2,2) --> (-1,1] : 702 if(x <= -1) 703 x += 2.; 704 else if (x > 1.) 705 x -= 2.; 706 if(x == 0. || x == 1.) 707 return 0.; 708 if(x == 0.5) 709 return 1.; 710 if(x == -0.5) 711 return -1.; 712 // otherwise 713 return sin(M_PI * x); 714 } 715 716 717 T tanpi(T: double)(T x) 718 { 719 if (isNaN(x)) 720 return x; 721 if(!isFinite(x)) 722 return T.nan; 723 724 x = fmod(x, 1.); // tan(pi(x + k)) == tan(pi x) for all integer k 725 // map (-1,1) --> (-1/2, 1/2] : 726 if(x <= -0.5) 727 x++; 728 else if(x > 0.5) 729 x--; 730 return (x == 0.) ? 0. : ((x == 0.5) ? T.nan : tan(M_PI * x)); 731 } 732 /* End of trig pi functions */ 733 734 T lgammafn_sign(T: double)(T x, int* sgn) 735 { 736 T ans, y, sinpiy; 737 738 //#ifdef NOMORE_FOR_THREADS 739 // static double xmax = 0.; 740 // static double dxrel = 0.; 741 // 742 // if (xmax == 0) {/* initialize machine dependent constants _ONCE_ */ 743 // xmax = d1mach(2)/log(d1mach(2));/* = 2.533 e305 for IEEE double */ 744 // dxrel = sqrt (d1mach(4));/* sqrt(Eps) ~ 1.49 e-8 for IEEE double */ 745 // } 746 //#else 747 /* For IEEE double precision DBL_EPSILON = 2^-52 = 2.220446049250313e-16 : 748 xmax = DBL_MAX / log(DBL_MAX) = 2^1024 / (1024 * log(2)) = 2^1014 / log(2) 749 dxrel = sqrt(DBL_EPSILON) = 2^-26 = 5^26 * 1e-26 (is *exact* below !) 750 */ 751 enum xmax = 2.5327372760800758e+305; 752 enum dxrel = 1.490116119384765625e-8; 753 754 if (sgn != null) *sgn = 1; 755 756 if(isNaN(x)) 757 return x; 758 759 760 if (sgn != null && x < 0 && fmod(floor(-x), 2.) == 0) 761 *sgn = -1; 762 763 if (x <= 0 && x == trunc(x)) { /* Negative integer argument */ 764 //ML_ERROR(ME_RANGE, "lgamma"); 765 return T.infinity;/* +Inf, since lgamma(x) = log|gamma(x)| */ 766 } 767 768 y = fabs(x); 769 770 if (y < 1e-306) 771 return -log(y); // denormalized range, R change 772 if (y <= 10) 773 return log(fabs(gammafn(x))); 774 /* 775 ELSE y = |x| > 10 ---------------------- */ 776 777 if (y > xmax) { 778 //ML_ERROR(ME_RANGE, "lgamma"); 779 return T.infinity; 780 } 781 782 if (x > 0) { /* i.e. y = x > 10 */ 783 if(x > 1e17) 784 return(x*(log(x) - 1.)); 785 else if(x > 4934720.) 786 return(M_LN_SQRT_2PI + (x - 0.5) * log(x) - x); 787 else 788 return M_LN_SQRT_2PI + (x - 0.5) * log(x) - x + lgammacor!T(x); 789 } 790 /* else: x < -10; y = -x */ 791 sinpiy = fabs(sinpi!T(y)); 792 793 if (sinpiy == 0) { /* Negative integer argument === 794 Now UNNECESSARY: caught above */ 795 //MATHLIB_WARNING(" ** should NEVER happen! *** [lgamma.c: Neg.int, y=%g]\n",y); 796 return T.nan; 797 } 798 799 ans = M_LN_SQRT_PId2 + (x - 0.5) * log(y) - x - log(sinpiy) - lgammacor!T(y); 800 801 if(fabs((x - trunc(x - 0.5)) * ans / x) < dxrel) { 802 803 /* The answer is less than half precision because 804 * the argument is too near a negative integer. */ 805 806 //ML_ERROR(ME_PRECISION, "lgamma"); 807 } 808 809 return ans; 810 } 811 812 T lgammafn(T: double)(T x) 813 { 814 return lgammafn_sign!T(x, null); 815 } 816 817 818 T stirlerr(T)(T n) 819 { 820 821 enum S0 = 0.083333333333333333333; /* 1/12 */ 822 enum S1 = 0.00277777777777777777778; /* 1/360 */ 823 enum S2 = 0.00079365079365079365079365; /* 1/1260 */ 824 enum S3 = 0.000595238095238095238095238; /* 1/1680 */ 825 enum S4 = 0.0008417508417508417508417508; /* 1/1188 */ 826 827 /* 828 error for 0, 0.5, 1.0, 1.5, ..., 14.5, 15.0. 829 */ 830 const static T[31] sferr_halves = [ 831 0.0, /* n=0 - wrong, place holder only */ 832 0.1534264097200273452913848, /* 0.5 */ 833 0.0810614667953272582196702, /* 1.0 */ 834 0.0548141210519176538961390, /* 1.5 */ 835 0.0413406959554092940938221, /* 2.0 */ 836 0.03316287351993628748511048, /* 2.5 */ 837 0.02767792568499833914878929, /* 3.0 */ 838 0.02374616365629749597132920, /* 3.5 */ 839 0.02079067210376509311152277, /* 4.0 */ 840 0.01848845053267318523077934, /* 4.5 */ 841 0.01664469118982119216319487, /* 5.0 */ 842 0.01513497322191737887351255, /* 5.5 */ 843 0.01387612882307074799874573, /* 6.0 */ 844 0.01281046524292022692424986, /* 6.5 */ 845 0.01189670994589177009505572, /* 7.0 */ 846 0.01110455975820691732662991, /* 7.5 */ 847 0.010411265261972096497478567, /* 8.0 */ 848 0.009799416126158803298389475, /* 8.5 */ 849 0.009255462182712732917728637, /* 9.0 */ 850 0.008768700134139385462952823, /* 9.5 */ 851 0.008330563433362871256469318, /* 10.0 */ 852 0.007934114564314020547248100, /* 10.5 */ 853 0.007573675487951840794972024, /* 11.0 */ 854 0.007244554301320383179543912, /* 11.5 */ 855 0.006942840107209529865664152, /* 12.0 */ 856 0.006665247032707682442354394, /* 12.5 */ 857 0.006408994188004207068439631, /* 13.0 */ 858 0.006171712263039457647532867, /* 13.5 */ 859 0.005951370112758847735624416, /* 14.0 */ 860 0.005746216513010115682023589, /* 14.5 */ 861 0.005554733551962801371038690 /* 15.0 */ 862 ]; 863 T nn; 864 865 if (n <= 15.0) { 866 nn = n + n; 867 if (nn == cast(int)nn) return(sferr_halves[cast(int)nn]); 868 return(lgammafn!T(n + 1.) - (n + 0.5)*log(n) + n - M_LN_SQRT_2PI); 869 } 870 871 nn = n*n; 872 if (n > 500) 873 return((S0 - S1/nn)/n); 874 if (n > 80) 875 return((S0 - (S1 - S2/nn)/nn)/n); 876 if (n > 35) 877 return((S0 - (S1 - (S2 - S3/nn)/nn)/nn)/n); 878 /* 15 < n <= 35 : */ 879 return ((S0 - (S1 - (S2 - (S3 - S4/nn)/nn)/nn)/nn)/n); 880 } 881 882 883 884 T gammafn(T: double)(T x) 885 { 886 const static T[42] gamcs = [ 887 +.8571195590989331421920062399942e-2, 888 +.4415381324841006757191315771652e-2, 889 +.5685043681599363378632664588789e-1, 890 -.4219835396418560501012500186624e-2, 891 +.1326808181212460220584006796352e-2, 892 -.1893024529798880432523947023886e-3, 893 +.3606925327441245256578082217225e-4, 894 -.6056761904460864218485548290365e-5, 895 +.1055829546302283344731823509093e-5, 896 -.1811967365542384048291855891166e-6, 897 +.3117724964715322277790254593169e-7, 898 -.5354219639019687140874081024347e-8, 899 +.9193275519859588946887786825940e-9, 900 -.1577941280288339761767423273953e-9, 901 +.2707980622934954543266540433089e-10, 902 -.4646818653825730144081661058933e-11, 903 +.7973350192007419656460767175359e-12, 904 -.1368078209830916025799499172309e-12, 905 +.2347319486563800657233471771688e-13, 906 -.4027432614949066932766570534699e-14, 907 +.6910051747372100912138336975257e-15, 908 -.1185584500221992907052387126192e-15, 909 +.2034148542496373955201026051932e-16, 910 -.3490054341717405849274012949108e-17, 911 +.5987993856485305567135051066026e-18, 912 -.1027378057872228074490069778431e-18, 913 +.1762702816060529824942759660748e-19, 914 -.3024320653735306260958772112042e-20, 915 +.5188914660218397839717833550506e-21, 916 -.8902770842456576692449251601066e-22, 917 +.1527474068493342602274596891306e-22, 918 -.2620731256187362900257328332799e-23, 919 +.4496464047830538670331046570666e-24, 920 -.7714712731336877911703901525333e-25, 921 +.1323635453126044036486572714666e-25, 922 -.2270999412942928816702313813333e-26, 923 +.3896418998003991449320816639999e-27, 924 -.6685198115125953327792127999999e-28, 925 +.1146998663140024384347613866666e-28, 926 -.1967938586345134677295103999999e-29, 927 +.3376448816585338090334890666666e-30, 928 -.5793070335782135784625493333333e-31 929 ]; 930 931 int i, n; 932 T y; 933 T sinpiy, value; 934 935 //static int ngam = 0; 936 //static T xmin = 0, xmax = 0., xsml = 0., dxrel = 0.; 937 938 /* Initialize machine dependent constants, the first time gamma() is called. 939 FIXME for threads ! */ 940 //if (ngam == 0) { 941 // ngam = chebyshev_init!T(gamcs, 42, EPSILON!T/20);/*was .1*d1mach(3)*/ 942 // gammalims!T(&xmin, &xmax);/*-> ./gammalims.c */ 943 // xsml = exp(fmax2(log(MIN!T), -log(MAX!T)) + 0.01); 944 // /* = exp(.01)*DBL_MIN = 2.247e-308 for IEEE */ 945 // dxrel = sqrt(EPSILON!T);/*was sqrt(d1mach(4)) */ 946 //} 947 948 /* For IEEE double precision DBL_EPSILON = 2^-52 = 2.220446049250313e-16 : 949 * (xmin, xmax) are non-trivial, see ./gammalims.c 950 * xsml = exp(.01)*DBL_MIN 951 * dxrel = sqrt(DBL_EPSILON) = 2 ^ -26 952 */ 953 const(int) ngam = 22; 954 const(T) xmin = -170.5674972726612; 955 const(T) xmax = 171.61447887182298; 956 const(T) xsml = 2.2474362225598545e-308; 957 const(T) dxrel = 1.490116119384765696e-8; 958 959 if(isNaN(x)) 960 return x; 961 962 /* If the argument is exactly zero or a negative integer 963 * then return NaN. */ 964 if (x == 0 || (x < 0 && x == round(x))) { 965 //ML_ERROR(ME_DOMAIN, "gammafn"); 966 return T.nan; 967 } 968 969 y = fabs(x); 970 971 if (y <= 10) { 972 973 /* Compute gamma(x) for -10 <= x <= 10 974 * Reduce the interval and find gamma(1 + y) for 0 <= y < 1 975 * first of all. */ 976 977 n = cast(int) x; 978 if(x < 0) 979 --n; 980 y = x - n;/* n = floor(x) ==> y in [ 0, 1 ) */ 981 --n; 982 value = chebyshev_eval!T(y * 2 - 1, gamcs.ptr, ngam) + .9375; 983 if (n == 0) 984 return value;/* x = 1.dddd = 1+y */ 985 986 if (n < 0) { 987 /* compute gamma(x) for -10 <= x < 1 */ 988 989 /* exact 0 or "-n" checked already above */ 990 991 /* The answer is less than half precision */ 992 /* because x too near a negative integer. */ 993 if (x < -0.5 && fabs(x - cast(int)(x - 0.5) / x) < dxrel) { 994 //ML_ERROR(ME_PRECISION, "gammafn"); 995 } 996 997 /* The argument is so close to 0 that the result would overflow. */ 998 if (y < xsml) { 999 //ML_ERROR(ME_RANGE, "gammafn"); 1000 if(x > 0) 1001 return T.infinity; 1002 else 1003 return -T.infinity; 1004 } 1005 1006 n = -n; 1007 1008 for (i = 0; i < n; i++) { 1009 value /= (x + i); 1010 } 1011 return value; 1012 } else { 1013 /* gamma(x) for 2 <= x <= 10 */ 1014 1015 for (i = 1; i <= n; i++) { 1016 value *= (y + i); 1017 } 1018 return value; 1019 } 1020 } 1021 else { 1022 /* gamma(x) for y = |x| > 10. */ 1023 1024 if (x > xmax) { /* Overflow */ 1025 //ML_ERROR(ME_RANGE, "gammafn"); 1026 return T.infinity; 1027 } 1028 1029 if (x < xmin) { /* Underflow */ 1030 //ML_ERROR(ME_UNDERFLOW, "gammafn"); 1031 return 0.; 1032 } 1033 1034 if(y <= 50 && y == cast(int)y) { /* compute (n - 1)! */ 1035 value = 1.; 1036 for (i = 2; i < y; i++) 1037 value *= i; 1038 } 1039 else { /* normal case */ 1040 value = exp((y - 0.5) * log(y) - y + M_LN_SQRT_2PI + 1041 ((2*y == cast(int)2*y)? stirlerr!T(y) : lgammacor!T(y))); 1042 } 1043 if (x > 0) 1044 return value; 1045 1046 if (fabs((x - cast(int)(x - 0.5))/x) < dxrel){ 1047 1048 /* The answer is less than half precision because */ 1049 /* the argument is too near a negative integer. */ 1050 1051 //ML_ERROR(ME_PRECISION, "gammafn"); 1052 } 1053 1054 sinpiy = sinpi!T(y); 1055 if (sinpiy == 0) { /* Negative integer arg - overflow */ 1056 //ML_ERROR(ME_RANGE, "gammafn"); 1057 return T.infinity; 1058 } 1059 1060 return -M_PI / (y * sinpiy * value); 1061 } 1062 } 1063 1064 1065 T bd0(T)(T x, T np) 1066 { 1067 T ej, s, s1, v; 1068 int j; 1069 1070 if(!isFinite(x) || !isFinite(np) || np == 0.0) 1071 return T.nan; 1072 1073 if (fabs(x - np) < 0.1*(x + np)) { 1074 v = (x - np)/(x + np); // might underflow to 0 1075 s = (x - np)*v;/* s using v -- change by MM */ 1076 if(fabs(s) < MIN!T) 1077 return s; 1078 ej = 2*x*v; 1079 v = v*v; 1080 for (j = 1; j < 1000; j++) { /* Taylor series; 1000: no infinite loop 1081 as |v| < .1, v^2000 is "zero" */ 1082 ej *= v;// = v^(2j+1) 1083 s1 = s + ej/((j << 1) + 1); 1084 if (s1 == s) /* last term was effectively 0 */ 1085 return s1 ; 1086 s = s1; 1087 } 1088 } 1089 /* else: | x - np | is not too small */ 1090 return(x*log(x/np) + np - x); 1091 } 1092 1093 1094 // called from dpois, dgamma, pgamma, dnbeta, dnbinom, dnchisq : 1095 T dpois_raw(T)(T x, T lambda, int give_log) 1096 { 1097 mixin R_D__1!give_log; 1098 mixin R_D__0!give_log; 1099 if (lambda == 0) 1100 return( (x == 0) ? R_D__1 : R_D__0 ); 1101 if (!isFinite(lambda)) 1102 return R_D__0; // including for the case where x = lambda = +Inf 1103 if (x < 0) 1104 return R_D__0; 1105 if (x <= lambda * MIN!T) 1106 return R_D_exp!T(-lambda, give_log); 1107 if (lambda < x * MIN!T) { 1108 if (!isFinite(x)) // lambda < x = +Inf 1109 return R_D__0; 1110 return(R_D_exp!T(-lambda + x*log(lambda) - lgammafn!T(x + 1), give_log)); 1111 } 1112 return(R_D_fexp!T( M_2PI*x, -stirlerr!T(x) - bd0(x, lambda), give_log)); 1113 } 1114 1115 1116 /* unif_rand */ 1117 /* 1118 static uint I1 = 1234, I2 = 5678; 1119 void set_seed(uint i1, uint i2) 1120 { 1121 I1 = i1; I2 = i2; 1122 } 1123 void get_seed(uint* i1, uint* i2) 1124 { 1125 *i1 = I1; *i2 = I2; 1126 } 1127 T unif_rand(T)() 1128 { 1129 import std.conv : octal; 1130 I1 = 36969*(I1 & octal!177777) + (I1>>16); 1131 I2 = 18000*(I2 & octal!177777) + (I2>>16); 1132 return ((I1 << 16)^(I2 & octal!177777)) * 2.328306437080797e-10; 1133 } 1134 */ 1135 1136 public import rmathd.rng.rng; 1137 auto unif_rand(T)(double lower = 0, double upper = 1) 1138 { 1139 return rand!double(lower, upper); 1140 } 1141 1142 void rng_demo() 1143 { 1144 import std.stdio: writeln; 1145 set_seed(789); 1146 foreach(i; 0..5) 1147 writeln(unif_rand!double()); 1148 1149 RandomNumberGenerator anotherRNG = new MINSTDRAND(); 1150 setRNG(anotherRNG); 1151 1152 writeln("Just after setRNG."); 1153 set_seed(101113); 1154 writeln("Next random numbers"); 1155 foreach(i; 0..5) 1156 writeln(unif_rand!double()); 1157 1158 setRNG(cast(RandomNumberGenerator)(new MINSTDRAND0())); 1159 1160 writeln("Next random numbers"); 1161 set_seed(50); 1162 foreach(i; 0..5) 1163 writeln(unif_rand!double()); 1164 } 1165 1166 1167 1168 T exp_rand(T)() 1169 { 1170 /* q[k-1] = sum(log(2)^k / k!) k=1,..,n, */ 1171 /* The highest n (here 16) is determined by q[n-1] = 1.0 */ 1172 /* within standard precision */ 1173 const static T[] q = 1174 [ 1175 0.6931471805599453, 1176 0.9333736875190459, 1177 0.9888777961838675, 1178 0.9984959252914960, 1179 0.9998292811061389, 1180 0.9999833164100727, 1181 0.9999985691438767, 1182 0.9999998906925558, 1183 0.9999999924734159, 1184 0.9999999995283275, 1185 0.9999999999728814, 1186 0.9999999999985598, 1187 0.9999999999999289, 1188 0.9999999999999968, 1189 0.9999999999999999, 1190 1.0000000000000000 1191 ]; 1192 1193 T a = 0.; 1194 T u = unif_rand!T(); /* precaution if u = 0 is ever returned */ 1195 while(u <= 0. || u >= 1.) 1196 u = unif_rand!T(); 1197 for (;;) { 1198 u += u; 1199 if (u > 1.) 1200 break; 1201 a += q[0]; 1202 } 1203 u -= 1.; 1204 1205 if (u <= q[0]) 1206 return a + u; 1207 1208 int i = 0; 1209 T ustar = unif_rand!T(), umin = ustar; 1210 do { 1211 ustar = unif_rand!T(); 1212 if (umin > ustar) 1213 umin = ustar; 1214 i++; 1215 } while (u > q[i]); 1216 return a + umin * q[0]; 1217 } 1218 1219 1220 auto dbinom_raw(T)(T x, T n, T p, T q, int give_log) 1221 { 1222 T lf, lc; 1223 1224 mixin R_D__0!give_log; 1225 mixin R_D__1!give_log; 1226 1227 if (p == 0) 1228 return((x == 0) ? R_D__1 : R_D__0); 1229 if (q == 0) 1230 return((x == n) ? R_D__1 : R_D__0); 1231 1232 if (x == 0) { 1233 if(n == 0) 1234 return R_D__1; 1235 lc = (p < 0.1) ? -bd0(n,n*q) - n*p : n*log(q); 1236 return( R_D_exp!T(lc, give_log) ); 1237 } 1238 if (x == n) { 1239 lc = (q < 0.1) ? -bd0(n,n*p) - n*q : n*log(p); 1240 return( R_D_exp!T(lc, give_log) ); 1241 } 1242 if (x < 0 || x > n) return( R_D__0 ); 1243 1244 /* n*p or n*q can underflow to zero if n and p or q are small. This 1245 used to occur in dbeta, and gives NaN as from R 2.3.0. */ 1246 lc = stirlerr!T(n) - stirlerr!T(x) - stirlerr!T(n - x) - bd0!T(x,n*p) - bd0!T(n - x, n*q); 1247 1248 /* f = (M_2PI*x*(n-x))/n; could overflow or underflow */ 1249 /* Upto R 2.7.1: 1250 * lf = log(M_2PI) + log(x) + log(n-x) - log(n); 1251 * -- following is much better for x << n : */ 1252 lf = M_LN_2PI + log(x) + log1p(- x/n); 1253 1254 return R_D_exp!T(lc - 0.5*lf, give_log); 1255 } 1256