1 // Written in the D programming language. 2 3 /** 4 This is a submodule of $(MREF std, math). 5 6 It contains several exponential and logarithm functions. 7 8 Copyright: Copyright The D Language Foundation 2000 - 2011. 9 D implementations of exp, expm1, exp2, log, log10, log1p, and log2 10 functions are based on the CEPHES math library, which is Copyright 11 (C) 2001 Stephen L. Moshier $(LT)steve@moshier.net$(GT) and are 12 incorporated herein by permission of the author. The author reserves 13 the right to distribute this material elsewhere under different 14 copying permissions. These modifications are distributed here under 15 the following terms: 16 License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). 17 Authors: $(HTTP digitalmars.com, Walter Bright), Don Clugston, 18 Conversion of CEPHES math library to D by Iain Buclaw and David Nadlinger 19 Source: $(PHOBOSSRC std/math/exponential.d) 20 21 Macros: 22 TABLE_SV = <table border="1" cellpadding="4" cellspacing="0"> 23 <caption>Special Values</caption> 24 $0</table> 25 NAN = $(RED NAN) 26 PLUSMN = ± 27 INFIN = ∞ 28 PLUSMNINF = ±∞ 29 LT = < 30 GT = > 31 */ 32 33 module std.math.exponential; 34 35 import std.traits : isFloatingPoint, isIntegral, isSigned, isUnsigned, Largest, Unqual; 36 37 static import core.math; 38 static import core.stdc.math; 39 40 version (LDC) 41 { 42 import ldc.intrinsics; 43 44 version (CRuntime_Microsoft) version = LDC_MSVCRT; 45 46 version (LDC_MSVCRT) {} 47 else version (Android) {} 48 else 49 { 50 version (X86) version = INLINE_YL2X; 51 version (X86_64) version = INLINE_YL2X; 52 } 53 } 54 55 version (DigitalMars) 56 { 57 version (OSX) { } // macOS 13 (M1) has issues emulating instruction 58 else version = INLINE_YL2X; // x87 has opcodes for these 59 } 60 61 version (D_InlineAsm_X86) version = InlineAsm_X86_Any; 62 version (D_InlineAsm_X86_64) version = InlineAsm_X86_Any; 63 64 version (LDC_MSVCRT) {} 65 else version (Android) {} 66 else version (InlineAsm_X86_Any) version = InlineAsm_X87; 67 version (InlineAsm_X87) 68 { 69 static assert(real.mant_dig == 64); 70 version (CRuntime_Microsoft) version = InlineAsm_X87_MSVC; 71 } 72 73 version (D_HardFloat) 74 { 75 // FloatingPointControl.clearExceptions() depends on version IeeeFlagsSupport 76 version (IeeeFlagsSupport) version = FloatingPointControlSupport; 77 } 78 79 /** 80 * Compute the value of x $(SUPERSCRIPT n), where n is an integer 81 */ 82 Unqual!F pow(F, G)(F x, G n) @nogc @trusted pure nothrow 83 if (isFloatingPoint!(F) && isIntegral!(G)) 84 { 85 version (none) 86 { 87 // LDC: Leads to linking error on MSVC x64 as the intrinsic maps to 88 // MSVC++ function `pow(double/float, int)` (a C++ template for 89 // Visual Studio 2015). 90 // Most likely not worth the effort anyway (and hindering CTFE). 91 pragma(inline, true); 92 return llvm_powi!(Unqual!F)(x, cast(int) n); 93 } 94 else 95 { 96 import std.traits : Unsigned; 97 98 real p = 1.0, v = void; 99 Unsigned!(Unqual!G) m = n; 100 101 if (n < 0) 102 { 103 if (n == -1) return 1 / x; 104 105 m = cast(typeof(m))(0 - n); 106 v = p / x; 107 } 108 else 109 { 110 switch (n) 111 { 112 case 0: 113 return 1.0; 114 case 1: 115 return x; 116 case 2: 117 return x * x; 118 default: 119 } 120 121 v = x; 122 } 123 124 while (1) 125 { 126 if (m & 1) 127 p *= v; 128 m >>= 1; 129 if (!m) 130 break; 131 v *= v; 132 } 133 return p; 134 } // !none 135 } 136 137 /// 138 @safe pure nothrow @nogc unittest 139 { 140 import std.math.operations : feqrel; 141 142 assert(pow(2.0, 5) == 32.0); 143 assert(pow(1.5, 9).feqrel(38.4433) > 16); 144 assert(pow(real.nan, 2) is real.nan); 145 assert(pow(real.infinity, 2) == real.infinity); 146 } 147 148 @safe pure nothrow @nogc unittest 149 { 150 import std.math.operations : isClose, feqrel; 151 152 // Make sure it instantiates and works properly on immutable values and 153 // with various integer and float types. 154 immutable real x = 46; 155 immutable float xf = x; 156 immutable double xd = x; 157 immutable uint one = 1; 158 immutable ushort two = 2; 159 immutable ubyte three = 3; 160 immutable ulong eight = 8; 161 162 immutable int neg1 = -1; 163 immutable short neg2 = -2; 164 immutable byte neg3 = -3; 165 immutable long neg8 = -8; 166 167 168 assert(pow(x,0) == 1.0); 169 assert(pow(xd,one) == x); 170 assert(pow(xf,two) == x * x); 171 assert(pow(x,three) == x * x * x); 172 assert(pow(x,eight) == (x * x) * (x * x) * (x * x) * (x * x)); 173 174 assert(pow(x, neg1) == 1 / x); 175 176 assert(isClose(pow(xd, neg2), cast(double) (1 / (x * x)), 1e-15)); 177 assert(isClose(pow(xf, neg8), cast(float) (1 / ((x * x) * (x * x) * (x * x) * (x * x))), 1e-15)); 178 179 assert(feqrel(pow(x, neg3), 1 / (x * x * x)) >= real.mant_dig - 1); 180 } 181 182 @safe @nogc nothrow unittest 183 { 184 import std.math.operations : isClose; 185 186 assert(isClose(pow(2.0L, 10L), 1024, 1e-18)); 187 } 188 189 // https://issues.dlang.org/show_bug.cgi?id=21601 190 @safe @nogc nothrow pure unittest 191 { 192 // When reals are large enough the results of pow(b, e) can be 193 // calculated correctly, if b is of type float or double and e is 194 // not too large. 195 static if (real.mant_dig >= 64) 196 { 197 // expected result: 3.790e-42 198 assert(pow(-513645318757045764096.0f, -2) > 0.0); 199 200 // expected result: 3.763915357831797e-309 201 assert(pow(-1.6299717435255677e+154, -2) > 0.0); 202 } 203 } 204 205 @safe @nogc nothrow unittest 206 { 207 import std.math.operations : isClose; 208 import std.math.traits : isInfinity; 209 210 static float f1 = 19100.0f; 211 static float f2 = 0.000012f; 212 213 assert(isClose(pow(f1,9), 3.3829868e+38f)); 214 assert(isInfinity(pow(f1,10))); 215 assert(pow(f2,9) > 0.0f); 216 assert(isClose(pow(f2,10), 0.0f, 0.0, float.min_normal)); 217 218 static double d1 = 21800.0; 219 static double d2 = 0.000012; 220 221 assert(isClose(pow(d1,71), 1.0725339442974e+308)); 222 assert(isInfinity(pow(d1,72))); 223 assert(pow(d2,65) > 0.0f); 224 assert(isClose(pow(d2,66), 0.0, 0.0, double.min_normal)); 225 226 static if (real.mant_dig == 64) // x87 227 { 228 static real r1 = 21950.0L; 229 static real r2 = 0.000011L; 230 231 assert(isClose(pow(r1,1136), 7.4066175654969242752260330529e+4931L)); 232 assert(isInfinity(pow(r1,1137))); 233 assert(pow(r2,998) > 0.0L); 234 assert(isClose(pow(r2,999), 0.0L, 0.0, real.min_normal)); 235 } 236 } 237 238 @safe @nogc nothrow pure unittest 239 { 240 import std.math.operations : isClose; 241 242 enum f1 = 19100.0f; 243 enum f2 = 0.000012f; 244 245 static assert(isClose(pow(f1,9), 3.3829868e+38f)); 246 static assert(pow(f1,10) > float.max); 247 static assert(pow(f2,9) > 0.0f); 248 static assert(isClose(pow(f2,10), 0.0f, 0.0, float.min_normal)); 249 250 enum d1 = 21800.0; 251 enum d2 = 0.000012; 252 253 static assert(isClose(pow(d1,71), 1.0725339442974e+308)); 254 static assert(pow(d1,72) > double.max); 255 static assert(pow(d2,65) > 0.0f); 256 static assert(isClose(pow(d2,66), 0.0, 0.0, double.min_normal)); 257 258 static if (real.mant_dig == 64) // x87 259 { 260 enum r1 = 21950.0L; 261 enum r2 = 0.000011L; 262 263 static assert(isClose(pow(r1,1136), 7.4066175654969242752260330529e+4931L)); 264 static assert(pow(r1,1137) > real.max); 265 static assert(pow(r2,998) > 0.0L); 266 static assert(isClose(pow(r2,999), 0.0L, 0.0, real.min_normal)); 267 } 268 } 269 270 /** 271 * Compute the power of two integral numbers. 272 * 273 * Params: 274 * x = base 275 * n = exponent 276 * 277 * Returns: 278 * x raised to the power of n. If n is negative the result is 1 / pow(x, -n), 279 * which is calculated as integer division with remainder. This may result in 280 * a division by zero error. 281 * 282 * If both x and n are 0, the result is 1. 283 * 284 * Throws: 285 * If x is 0 and n is negative, the result is the same as the result of a 286 * division by zero. 287 */ 288 typeof(Unqual!(F).init * Unqual!(G).init) pow(F, G)(F x, G n) @nogc @trusted pure nothrow 289 if (isIntegral!(F) && isIntegral!(G)) 290 { 291 import std.traits : isSigned; 292 293 typeof(return) p, v = void; 294 Unqual!G m = n; 295 296 static if (isSigned!(F)) 297 { 298 if (x == -1) return cast(typeof(return)) (m & 1 ? -1 : 1); 299 } 300 static if (isSigned!(G)) 301 { 302 if (x == 0 && m <= -1) return x / 0; 303 } 304 if (x == 1) return 1; 305 static if (isSigned!(G)) 306 { 307 if (m < 0) return 0; 308 } 309 310 switch (m) 311 { 312 case 0: 313 p = 1; 314 break; 315 316 case 1: 317 p = x; 318 break; 319 320 case 2: 321 p = x * x; 322 break; 323 324 default: 325 v = x; 326 p = 1; 327 while (1) 328 { 329 if (m & 1) 330 p *= v; 331 m >>= 1; 332 if (!m) 333 break; 334 v *= v; 335 } 336 break; 337 } 338 return p; 339 } 340 341 /// 342 @safe pure nothrow @nogc unittest 343 { 344 assert(pow(2, 3) == 8); 345 assert(pow(3, 2) == 9); 346 347 assert(pow(2, 10) == 1_024); 348 assert(pow(2, 20) == 1_048_576); 349 assert(pow(2, 30) == 1_073_741_824); 350 351 assert(pow(0, 0) == 1); 352 353 assert(pow(1, -5) == 1); 354 assert(pow(1, -6) == 1); 355 assert(pow(-1, -5) == -1); 356 assert(pow(-1, -6) == 1); 357 358 assert(pow(-2, 5) == -32); 359 assert(pow(-2, -5) == 0); 360 assert(pow(cast(double) -2, -5) == -0.03125); 361 } 362 363 @safe pure nothrow @nogc unittest 364 { 365 immutable int one = 1; 366 immutable byte two = 2; 367 immutable ubyte three = 3; 368 immutable short four = 4; 369 immutable long ten = 10; 370 371 assert(pow(two, three) == 8); 372 assert(pow(two, ten) == 1024); 373 assert(pow(one, ten) == 1); 374 assert(pow(ten, four) == 10_000); 375 assert(pow(four, 10) == 1_048_576); 376 assert(pow(three, four) == 81); 377 } 378 379 // https://issues.dlang.org/show_bug.cgi?id=7006 380 @safe pure nothrow @nogc unittest 381 { 382 assert(pow(5, -1) == 0); 383 assert(pow(-5, -1) == 0); 384 assert(pow(5, -2) == 0); 385 assert(pow(-5, -2) == 0); 386 assert(pow(-1, int.min) == 1); 387 assert(pow(-2, int.min) == 0); 388 389 assert(pow(4294967290UL,2) == 18446744022169944100UL); 390 assert(pow(0,uint.max) == 0); 391 } 392 393 /**Computes integer to floating point powers.*/ 394 real pow(I, F)(I x, F y) @nogc @trusted pure nothrow 395 if (isIntegral!I && isFloatingPoint!F) 396 { 397 return pow(cast(real) x, cast(Unqual!F) y); 398 } 399 400 /// 401 @safe pure nothrow @nogc unittest 402 { 403 assert(pow(2, 5.0) == 32.0); 404 assert(pow(7, 3.0) == 343.0); 405 assert(pow(2, real.nan) is real.nan); 406 assert(pow(2, real.infinity) == real.infinity); 407 } 408 409 /** 410 * Calculates x$(SUPERSCRIPT y). 411 * 412 * $(TABLE_SV 413 * $(TR $(TH x) $(TH y) $(TH pow(x, y)) 414 * $(TH div 0) $(TH invalid?)) 415 * $(TR $(TD anything) $(TD $(PLUSMN)0.0) $(TD 1.0) 416 * $(TD no) $(TD no) ) 417 * $(TR $(TD |x| $(GT) 1) $(TD +$(INFIN)) $(TD +$(INFIN)) 418 * $(TD no) $(TD no) ) 419 * $(TR $(TD |x| $(LT) 1) $(TD +$(INFIN)) $(TD +0.0) 420 * $(TD no) $(TD no) ) 421 * $(TR $(TD |x| $(GT) 1) $(TD -$(INFIN)) $(TD +0.0) 422 * $(TD no) $(TD no) ) 423 * $(TR $(TD |x| $(LT) 1) $(TD -$(INFIN)) $(TD +$(INFIN)) 424 * $(TD no) $(TD no) ) 425 * $(TR $(TD +$(INFIN)) $(TD $(GT) 0.0) $(TD +$(INFIN)) 426 * $(TD no) $(TD no) ) 427 * $(TR $(TD +$(INFIN)) $(TD $(LT) 0.0) $(TD +0.0) 428 * $(TD no) $(TD no) ) 429 * $(TR $(TD -$(INFIN)) $(TD odd integer $(GT) 0.0) $(TD -$(INFIN)) 430 * $(TD no) $(TD no) ) 431 * $(TR $(TD -$(INFIN)) $(TD $(GT) 0.0, not odd integer) $(TD +$(INFIN)) 432 * $(TD no) $(TD no)) 433 * $(TR $(TD -$(INFIN)) $(TD odd integer $(LT) 0.0) $(TD -0.0) 434 * $(TD no) $(TD no) ) 435 * $(TR $(TD -$(INFIN)) $(TD $(LT) 0.0, not odd integer) $(TD +0.0) 436 * $(TD no) $(TD no) ) 437 * $(TR $(TD $(PLUSMN)1.0) $(TD $(PLUSMN)$(INFIN)) $(TD -$(NAN)) 438 * $(TD no) $(TD yes) ) 439 * $(TR $(TD $(LT) 0.0) $(TD finite, nonintegral) $(TD $(NAN)) 440 * $(TD no) $(TD yes)) 441 * $(TR $(TD $(PLUSMN)0.0) $(TD odd integer $(LT) 0.0) $(TD $(PLUSMNINF)) 442 * $(TD yes) $(TD no) ) 443 * $(TR $(TD $(PLUSMN)0.0) $(TD $(LT) 0.0, not odd integer) $(TD +$(INFIN)) 444 * $(TD yes) $(TD no)) 445 * $(TR $(TD $(PLUSMN)0.0) $(TD odd integer $(GT) 0.0) $(TD $(PLUSMN)0.0) 446 * $(TD no) $(TD no) ) 447 * $(TR $(TD $(PLUSMN)0.0) $(TD $(GT) 0.0, not odd integer) $(TD +0.0) 448 * $(TD no) $(TD no) ) 449 * ) 450 */ 451 Unqual!(Largest!(F, G)) pow(F, G)(F x, G y) @nogc @trusted pure nothrow 452 if (isFloatingPoint!(F) && isFloatingPoint!(G)) 453 { 454 import core.math : fabs, sqrt; 455 import std.math.traits : isInfinity, isNaN, signbit; 456 457 alias Float = typeof(return); 458 459 version (none) // LDC FIXME: Use of this LLVM intrinsic causes a unit test failure 460 { 461 pragma(inline, true); 462 return llvm_pow!(Float)(x, y); 463 } 464 else 465 { 466 static real impl(real x, real y) @nogc pure nothrow 467 { 468 // Special cases. 469 if (isNaN(y)) 470 return y; 471 if (isNaN(x) && y != 0.0) 472 return x; 473 474 // Even if x is NaN. 475 if (y == 0.0) 476 return 1.0; 477 if (y == 1.0) 478 return x; 479 480 if (isInfinity(y)) 481 { 482 if (isInfinity(x)) 483 { 484 if (!signbit(y) && !signbit(x)) 485 return F.infinity; 486 else 487 return F.nan; 488 } 489 else if (fabs(x) > 1) 490 { 491 if (signbit(y)) 492 return +0.0; 493 else 494 return F.infinity; 495 } 496 else if (fabs(x) == 1) 497 { 498 return F.nan; 499 } 500 else // < 1 501 { 502 if (signbit(y)) 503 return F.infinity; 504 else 505 return +0.0; 506 } 507 } 508 if (isInfinity(x)) 509 { 510 if (signbit(x)) 511 { 512 long i = cast(long) y; 513 if (y > 0.0) 514 { 515 if (i == y && i & 1) 516 return -F.infinity; 517 else if (i == y) 518 return F.infinity; 519 else 520 return -F.nan; 521 } 522 else if (y < 0.0) 523 { 524 if (i == y && i & 1) 525 return -0.0; 526 else if (i == y) 527 return +0.0; 528 else 529 return F.nan; 530 } 531 } 532 else 533 { 534 if (y > 0.0) 535 return F.infinity; 536 else if (y < 0.0) 537 return +0.0; 538 } 539 } 540 541 if (x == 0.0) 542 { 543 if (signbit(x)) 544 { 545 long i = cast(long) y; 546 if (y > 0.0) 547 { 548 if (i == y && i & 1) 549 return -0.0; 550 else 551 return +0.0; 552 } 553 else if (y < 0.0) 554 { 555 if (i == y && i & 1) 556 return -F.infinity; 557 else 558 return F.infinity; 559 } 560 } 561 else 562 { 563 if (y > 0.0) 564 return +0.0; 565 else if (y < 0.0) 566 return F.infinity; 567 } 568 } 569 if (x == 1.0) 570 return 1.0; 571 572 if (y >= F.max) 573 { 574 if ((x > 0.0 && x < 1.0) || (x > -1.0 && x < 0.0)) 575 return 0.0; 576 if (x > 1.0 || x < -1.0) 577 return F.infinity; 578 } 579 if (y <= -F.max) 580 { 581 if ((x > 0.0 && x < 1.0) || (x > -1.0 && x < 0.0)) 582 return F.infinity; 583 if (x > 1.0 || x < -1.0) 584 return 0.0; 585 } 586 587 if (x >= F.max) 588 { 589 if (y > 0.0) 590 return F.infinity; 591 else 592 return 0.0; 593 } 594 if (x <= -F.max) 595 { 596 long i = cast(long) y; 597 if (y > 0.0) 598 { 599 if (i == y && i & 1) 600 return -F.infinity; 601 else 602 return F.infinity; 603 } 604 else if (y < 0.0) 605 { 606 if (i == y && i & 1) 607 return -0.0; 608 else 609 return +0.0; 610 } 611 } 612 613 // Integer power of x. 614 long iy = cast(long) y; 615 if (iy == y && fabs(y) < 32_768.0) 616 return pow(x, iy); 617 618 real sign = 1.0; 619 if (x < 0) 620 { 621 // Result is real only if y is an integer 622 // Check for a non-zero fractional part 623 enum maxOdd = pow(2.0L, real.mant_dig) - 1.0L; 624 static if (maxOdd > ulong.max) 625 { 626 // Generic method, for any FP type 627 import std.math.rounding : floor; 628 if (floor(y) != y) 629 return sqrt(x); // Complex result -- create a NaN 630 631 const hy = 0.5 * y; 632 if (floor(hy) != hy) 633 sign = -1.0; 634 } 635 else 636 { 637 // Much faster, if ulong has enough precision 638 const absY = fabs(y); 639 if (absY <= maxOdd) 640 { 641 const uy = cast(ulong) absY; 642 if (uy != absY) 643 return sqrt(x); // Complex result -- create a NaN 644 645 if (uy & 1) 646 sign = -1.0; 647 } 648 } 649 x = -x; 650 } 651 version (INLINE_YL2X) 652 { 653 // If x > 0, x ^^ y == 2 ^^ ( y * log2(x) ) 654 // TODO: This is not accurate in practice. A fast and accurate 655 // (though complicated) method is described in: 656 // "An efficient rounding boundary test for pow(x, y) 657 // in double precision", C.Q. Lauter and V. Lefèvre, INRIA (2007). 658 return sign * exp2( core.math.yl2x(x, y) ); 659 } 660 else 661 { 662 // If x > 0, x ^^ y == 2 ^^ ( y * log2(x) ) 663 // TODO: This is not accurate in practice. A fast and accurate 664 // (though complicated) method is described in: 665 // "An efficient rounding boundary test for pow(x, y) 666 // in double precision", C.Q. Lauter and V. Lefèvre, INRIA (2007). 667 Float w = exp2(y * log2(x)); 668 return sign * w; 669 } 670 } 671 return impl(x, y); 672 } // !none 673 } 674 675 /// 676 @safe pure nothrow @nogc unittest 677 { 678 import std.math.operations : isClose; 679 680 assert(isClose(pow(2.0, 3.0), 8.0)); 681 assert(isClose(pow(1.5, 10.0), 57.6650390625)); 682 683 // square root of 9 684 assert(isClose(pow(9.0, 0.5), 3.0)); 685 // 10th root of 1024 686 assert(isClose(pow(1024.0, 0.1), 2.0)); 687 688 assert(isClose(pow(-4.0, 3.0), -64.0)); 689 690 // reciprocal of 4 ^^ 2 691 assert(isClose(pow(4.0, -2.0), 0.0625)); 692 // reciprocal of (-2) ^^ 3 693 assert(isClose(pow(-2.0, -3.0), -0.125)); 694 695 assert(isClose(pow(-2.5, 3.0), -15.625)); 696 // reciprocal of 2.5 ^^ 3 697 assert(isClose(pow(2.5, -3.0), 0.064)); 698 // reciprocal of (-2.5) ^^ 3 699 assert(isClose(pow(-2.5, -3.0), -0.064)); 700 701 // reciprocal of square root of 4 702 assert(isClose(pow(4.0, -0.5), 0.5)); 703 704 // per definition 705 assert(isClose(pow(0.0, 0.0), 1.0)); 706 } 707 708 /// 709 @safe pure nothrow @nogc unittest 710 { 711 import std.math.operations : isClose; 712 713 // the result is a complex number 714 // which cannot be represented as floating point number 715 import std.math.traits : isNaN; 716 assert(isNaN(pow(-2.5, -1.5))); 717 718 // use the ^^-operator of std.complex instead 719 import std.complex : complex; 720 auto c1 = complex(-2.5, 0.0); 721 auto c2 = complex(-1.5, 0.0); 722 auto result = c1 ^^ c2; 723 // exact result apparently depends on `real` precision => increased tolerance 724 assert(isClose(result.re, -4.64705438e-17, 2e-4)); 725 assert(isClose(result.im, 2.52982e-1, 2e-4)); 726 } 727 728 @safe pure nothrow @nogc unittest 729 { 730 import std.math.traits : isNaN; 731 732 assert(pow(1.5, real.infinity) == real.infinity); 733 assert(pow(0.5, real.infinity) == 0.0); 734 assert(pow(1.5, -real.infinity) == 0.0); 735 assert(pow(0.5, -real.infinity) == real.infinity); 736 assert(pow(real.infinity, 1.0) == real.infinity); 737 assert(pow(real.infinity, -1.0) == 0.0); 738 assert(pow(real.infinity, real.infinity) == real.infinity); 739 assert(pow(-real.infinity, 1.0) == -real.infinity); 740 assert(pow(-real.infinity, 2.0) == real.infinity); 741 assert(pow(-real.infinity, -1.0) == -0.0); 742 assert(pow(-real.infinity, -2.0) == 0.0); 743 assert(isNaN(pow(1.0, real.infinity))); 744 assert(pow(0.0, -1.0) == real.infinity); 745 assert(pow(real.nan, 0.0) == 1.0); 746 assert(isNaN(pow(real.nan, 3.0))); 747 assert(isNaN(pow(3.0, real.nan))); 748 } 749 750 @safe @nogc nothrow unittest 751 { 752 import std.math.operations : isClose; 753 754 assert(isClose(pow(2.0L, 10.0L), 1024, 1e-18)); 755 } 756 757 @safe pure nothrow @nogc unittest 758 { 759 import std.math.operations : isClose; 760 import std.math.traits : isIdentical, isNaN; 761 import std.math.constants : PI; 762 763 // Test all the special values. These unittests can be run on Windows 764 // by temporarily changing the version (linux) to version (all). 765 immutable float zero = 0; 766 immutable real one = 1; 767 immutable double two = 2; 768 immutable float three = 3; 769 immutable float fnan = float.nan; 770 immutable double dnan = double.nan; 771 immutable real rnan = real.nan; 772 immutable dinf = double.infinity; 773 immutable rninf = -real.infinity; 774 775 assert(pow(fnan, zero) == 1); 776 assert(pow(dnan, zero) == 1); 777 assert(pow(rnan, zero) == 1); 778 779 assert(pow(two, dinf) == double.infinity); 780 assert(isIdentical(pow(0.2f, dinf), +0.0)); 781 assert(pow(0.99999999L, rninf) == real.infinity); 782 assert(isIdentical(pow(1.000000001, rninf), +0.0)); 783 assert(pow(dinf, 0.001) == dinf); 784 assert(isIdentical(pow(dinf, -0.001), +0.0)); 785 assert(pow(rninf, 3.0L) == rninf); 786 assert(pow(rninf, 2.0L) == real.infinity); 787 assert(isIdentical(pow(rninf, -3.0), -0.0)); 788 assert(isIdentical(pow(rninf, -2.0), +0.0)); 789 790 // @@@BUG@@@ somewhere 791 version (OSX) {} else assert(isNaN(pow(one, dinf))); 792 version (OSX) {} else assert(isNaN(pow(-one, dinf))); 793 assert(isNaN(pow(-0.2, PI))); 794 // boundary cases. Note that epsilon == 2^^-n for some n, 795 // so 1/epsilon == 2^^n is always even. 796 assert(pow(-1.0L, 1/real.epsilon - 1.0L) == -1.0L); 797 static if (LLVM_version >= 1300) { /* LDC: on x86, yields -1 with enabled optimizations */ } else 798 assert(pow(-1.0L, 1/real.epsilon) == 1.0L); 799 assert(isNaN(pow(-1.0L, 1/real.epsilon-0.5L))); 800 assert(isNaN(pow(-1.0L, -1/real.epsilon+0.5L))); 801 802 assert(pow(0.0, -3.0) == double.infinity); 803 assert(pow(-0.0, -3.0) == -double.infinity); 804 assert(pow(0.0, -PI) == double.infinity); 805 assert(pow(-0.0, -PI) == double.infinity); 806 assert(isIdentical(pow(0.0, 5.0), 0.0)); 807 assert(isIdentical(pow(-0.0, 5.0), -0.0)); 808 assert(isIdentical(pow(0.0, 6.0), 0.0)); 809 assert(isIdentical(pow(-0.0, 6.0), 0.0)); 810 811 // https://issues.dlang.org/show_bug.cgi?id=14786 fixed 812 immutable real maxOdd = pow(2.0L, real.mant_dig) - 1.0L; 813 assert(pow(-1.0L, maxOdd) == -1.0L); 814 assert(pow(-1.0L, -maxOdd) == -1.0L); 815 assert(pow(-1.0L, maxOdd + 1.0L) == 1.0L); 816 assert(pow(-1.0L, -maxOdd + 1.0L) == 1.0L); 817 assert(pow(-1.0L, maxOdd - 1.0L) == 1.0L); 818 assert(pow(-1.0L, -maxOdd - 1.0L) == 1.0L); 819 820 // Now, actual numbers. 821 assert(isClose(pow(two, three), 8.0)); 822 assert(isClose(pow(two, -2.5), 0.1767766953)); 823 824 // Test integer to float power. 825 immutable uint twoI = 2; 826 assert(isClose(pow(twoI, three), 8.0)); 827 } 828 829 // https://issues.dlang.org/show_bug.cgi?id=20508 830 @safe pure nothrow @nogc unittest 831 { 832 import std.math.traits : isNaN; 833 834 assert(isNaN(pow(-double.infinity, 0.5))); 835 836 assert(isNaN(pow(-real.infinity, real.infinity))); 837 assert(isNaN(pow(-real.infinity, -real.infinity))); 838 assert(isNaN(pow(-real.infinity, 1.234))); 839 assert(isNaN(pow(-real.infinity, -0.751))); 840 assert(pow(-real.infinity, 0.0) == 1.0); 841 } 842 843 /** Computes the value of a positive integer `x`, raised to the power `n`, modulo `m`. 844 * 845 * Params: 846 * x = base 847 * n = exponent 848 * m = modulus 849 * 850 * Returns: 851 * `x` to the power `n`, modulo `m`. 852 * The return type is the largest of `x`'s and `m`'s type. 853 * 854 * The function requires that all values have unsigned types. 855 */ 856 Unqual!(Largest!(F, H)) powmod(F, G, H)(F x, G n, H m) 857 if (isUnsigned!F && isUnsigned!G && isUnsigned!H) 858 { 859 import std.meta : AliasSeq; 860 861 alias T = Unqual!(Largest!(F, H)); 862 static if (T.sizeof <= 4) 863 { 864 alias DoubleT = AliasSeq!(void, ushort, uint, void, ulong)[T.sizeof]; 865 } 866 867 static T mulmod(T a, T b, T c) 868 { 869 static if (T.sizeof == 8) 870 { 871 static T addmod(T a, T b, T c) 872 { 873 b = c - b; 874 if (a >= b) 875 return a - b; 876 else 877 return c - b + a; 878 } 879 880 T result = 0, tmp; 881 882 b %= c; 883 while (a > 0) 884 { 885 if (a & 1) 886 result = addmod(result, b, c); 887 888 a >>= 1; 889 b = addmod(b, b, c); 890 } 891 892 return result; 893 } 894 else 895 { 896 DoubleT result = cast(DoubleT) (cast(DoubleT) a * cast(DoubleT) b); 897 return result % c; 898 } 899 } 900 901 T base = x, result = 1, modulus = m; 902 Unqual!G exponent = n; 903 904 while (exponent > 0) 905 { 906 if (exponent & 1) 907 result = mulmod(result, base, modulus); 908 909 base = mulmod(base, base, modulus); 910 exponent >>= 1; 911 } 912 913 return result; 914 } 915 916 /// 917 @safe pure nothrow @nogc unittest 918 { 919 assert(powmod(1U, 10U, 3U) == 1); 920 assert(powmod(3U, 2U, 6U) == 3); 921 assert(powmod(5U, 5U, 15U) == 5); 922 assert(powmod(2U, 3U, 5U) == 3); 923 assert(powmod(2U, 4U, 5U) == 1); 924 assert(powmod(2U, 5U, 5U) == 2); 925 } 926 927 @safe pure nothrow @nogc unittest 928 { 929 ulong a = 18446744073709551615u, b = 20u, c = 18446744073709551610u; 930 assert(powmod(a, b, c) == 95367431640625u); 931 a = 100; b = 7919; c = 18446744073709551557u; 932 assert(powmod(a, b, c) == 18223853583554725198u); 933 a = 117; b = 7919; c = 18446744073709551557u; 934 assert(powmod(a, b, c) == 11493139548346411394u); 935 a = 134; b = 7919; c = 18446744073709551557u; 936 assert(powmod(a, b, c) == 10979163786734356774u); 937 a = 151; b = 7919; c = 18446744073709551557u; 938 assert(powmod(a, b, c) == 7023018419737782840u); 939 a = 168; b = 7919; c = 18446744073709551557u; 940 assert(powmod(a, b, c) == 58082701842386811u); 941 a = 185; b = 7919; c = 18446744073709551557u; 942 assert(powmod(a, b, c) == 17423478386299876798u); 943 a = 202; b = 7919; c = 18446744073709551557u; 944 assert(powmod(a, b, c) == 5522733478579799075u); 945 a = 219; b = 7919; c = 18446744073709551557u; 946 assert(powmod(a, b, c) == 15230218982491623487u); 947 a = 236; b = 7919; c = 18446744073709551557u; 948 assert(powmod(a, b, c) == 5198328724976436000u); 949 950 a = 0; b = 7919; c = 18446744073709551557u; 951 assert(powmod(a, b, c) == 0); 952 a = 123; b = 0; c = 18446744073709551557u; 953 assert(powmod(a, b, c) == 1); 954 955 immutable ulong a1 = 253, b1 = 7919, c1 = 18446744073709551557u; 956 assert(powmod(a1, b1, c1) == 3883707345459248860u); 957 958 uint x = 100 ,y = 7919, z = 1844674407u; 959 assert(powmod(x, y, z) == 1613100340u); 960 x = 134; y = 7919; z = 1844674407u; 961 assert(powmod(x, y, z) == 734956622u); 962 x = 151; y = 7919; z = 1844674407u; 963 assert(powmod(x, y, z) == 1738696945u); 964 x = 168; y = 7919; z = 1844674407u; 965 assert(powmod(x, y, z) == 1247580927u); 966 x = 185; y = 7919; z = 1844674407u; 967 assert(powmod(x, y, z) == 1293855176u); 968 x = 202; y = 7919; z = 1844674407u; 969 assert(powmod(x, y, z) == 1566963682u); 970 x = 219; y = 7919; z = 1844674407u; 971 assert(powmod(x, y, z) == 181227807u); 972 x = 236; y = 7919; z = 1844674407u; 973 assert(powmod(x, y, z) == 217988321u); 974 x = 253; y = 7919; z = 1844674407u; 975 assert(powmod(x, y, z) == 1588843243u); 976 977 x = 0; y = 7919; z = 184467u; 978 assert(powmod(x, y, z) == 0); 979 x = 123; y = 0; z = 1844674u; 980 assert(powmod(x, y, z) == 1); 981 982 immutable ubyte x1 = 117; 983 immutable uint y1 = 7919; 984 immutable uint z1 = 1844674407u; 985 auto res = powmod(x1, y1, z1); 986 assert(is(typeof(res) == uint)); 987 assert(res == 9479781u); 988 989 immutable ushort x2 = 123; 990 immutable uint y2 = 203; 991 immutable ubyte z2 = 113; 992 auto res2 = powmod(x2, y2, z2); 993 assert(is(typeof(res2) == ushort)); 994 assert(res2 == 42u); 995 } 996 997 /** 998 * Calculates e$(SUPERSCRIPT x). 999 * 1000 * $(TABLE_SV 1001 * $(TR $(TH x) $(TH e$(SUPERSCRIPT x)) ) 1002 * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) ) 1003 * $(TR $(TD -$(INFIN)) $(TD +0.0) ) 1004 * $(TR $(TD $(NAN)) $(TD $(NAN)) ) 1005 * ) 1006 */ 1007 version (none) // LDC FIXME: Use of this LLVM intrinsic causes a unit test failure 1008 { 1009 pragma(inline, true): 1010 real exp(real x) @safe pure nothrow @nogc { return llvm_exp(x); } 1011 ///ditto 1012 double exp(double x) @safe pure nothrow @nogc { return llvm_exp(x); } 1013 ///ditto 1014 float exp(float x) @safe pure nothrow @nogc { return llvm_exp(x); } 1015 } 1016 else 1017 { 1018 1019 pragma(inline, true) 1020 real exp(real x) @trusted pure nothrow @nogc // TODO: @safe 1021 { 1022 version (InlineAsm_X87) 1023 { 1024 import std.math.constants : LOG2E; 1025 1026 // e^^x = 2^^(LOG2E*x) 1027 // (This is valid because the overflow & underflow limits for exp 1028 // and exp2 are so similar). 1029 if (!__ctfe) 1030 return exp2Asm(LOG2E*x); 1031 } 1032 return expImpl(x); 1033 } 1034 1035 /// ditto 1036 pragma(inline, true) 1037 double exp(double x) @safe pure nothrow @nogc { return __ctfe ? cast(double) exp(cast(real) x) : expImpl(x); } 1038 1039 /// ditto 1040 pragma(inline, true) 1041 float exp(float x) @safe pure nothrow @nogc { return __ctfe ? cast(float) exp(cast(real) x) : expImpl(x); } 1042 1043 } // !none 1044 1045 /// 1046 @safe unittest 1047 { 1048 import std.math.operations : feqrel; 1049 import std.math.constants : E; 1050 1051 assert(exp(0.0) == 1.0); 1052 assert(exp(3.0).feqrel(E * E * E) > 16); 1053 } 1054 1055 private T expImpl(T)(T x) @safe pure nothrow @nogc 1056 { 1057 import std.math : floatTraits, RealFormat; 1058 import std.math.traits : isNaN; 1059 import std.math.rounding : floor; 1060 import std.math.algebraic : poly; 1061 import std.math.constants : LOG2E; 1062 1063 alias F = floatTraits!T; 1064 static if (F.realFormat == RealFormat.ieeeSingle) 1065 { 1066 static immutable T[6] P = [ 1067 5.0000001201E-1, 1068 1.6666665459E-1, 1069 4.1665795894E-2, 1070 8.3334519073E-3, 1071 1.3981999507E-3, 1072 1.9875691500E-4, 1073 ]; 1074 1075 enum T C1 = 0.693359375; 1076 enum T C2 = -2.12194440e-4; 1077 1078 // Overflow and Underflow limits. 1079 enum T OF = 88.72283905206835; 1080 enum T UF = -103.278929903431851103; // ln(2^-149) 1081 } 1082 else static if (F.realFormat == RealFormat.ieeeDouble) 1083 { 1084 // Coefficients for exp(x) 1085 static immutable T[3] P = [ 1086 9.99999999999999999910E-1L, 1087 3.02994407707441961300E-2L, 1088 1.26177193074810590878E-4L, 1089 ]; 1090 static immutable T[4] Q = [ 1091 2.00000000000000000009E0L, 1092 2.27265548208155028766E-1L, 1093 2.52448340349684104192E-3L, 1094 3.00198505138664455042E-6L, 1095 ]; 1096 1097 // C1 + C2 = LN2. 1098 enum T C1 = 6.93145751953125E-1; 1099 enum T C2 = 1.42860682030941723212E-6; 1100 1101 // Overflow and Underflow limits. 1102 enum T OF = 7.09782712893383996732E2; // ln((1-2^-53) * 2^1024) 1103 enum T UF = -7.451332191019412076235E2; // ln(2^-1075) 1104 } 1105 else static if (F.realFormat == RealFormat.ieeeExtended || 1106 F.realFormat == RealFormat.ieeeExtended53) 1107 { 1108 // Coefficients for exp(x) 1109 static immutable T[3] P = [ 1110 9.9999999999999999991025E-1L, 1111 3.0299440770744196129956E-2L, 1112 1.2617719307481059087798E-4L, 1113 ]; 1114 static immutable T[4] Q = [ 1115 2.0000000000000000000897E0L, 1116 2.2726554820815502876593E-1L, 1117 2.5244834034968410419224E-3L, 1118 3.0019850513866445504159E-6L, 1119 ]; 1120 1121 // C1 + C2 = LN2. 1122 enum T C1 = 6.9314575195312500000000E-1L; 1123 enum T C2 = 1.4286068203094172321215E-6L; 1124 1125 // Overflow and Underflow limits. 1126 enum T OF = 1.1356523406294143949492E4L; // ln((1-2^-64) * 2^16384) 1127 enum T UF = -1.13994985314888605586758E4L; // ln(2^-16446) 1128 } 1129 else static if (F.realFormat == RealFormat.ieeeQuadruple) 1130 { 1131 // Coefficients for exp(x) - 1 1132 static immutable T[5] P = [ 1133 9.999999999999999999999999999999999998502E-1L, 1134 3.508710990737834361215404761139478627390E-2L, 1135 2.708775201978218837374512615596512792224E-4L, 1136 6.141506007208645008909088812338454698548E-7L, 1137 3.279723985560247033712687707263393506266E-10L 1138 ]; 1139 static immutable T[6] Q = [ 1140 2.000000000000000000000000000000000000150E0, 1141 2.368408864814233538909747618894558968880E-1L, 1142 3.611828913847589925056132680618007270344E-3L, 1143 1.504792651814944826817779302637284053660E-5L, 1144 1.771372078166251484503904874657985291164E-8L, 1145 2.980756652081995192255342779918052538681E-12L 1146 ]; 1147 1148 // C1 + C2 = LN2. 1149 enum T C1 = 6.93145751953125E-1L; 1150 enum T C2 = 1.428606820309417232121458176568075500134E-6L; 1151 1152 // Overflow and Underflow limits. 1153 enum T OF = 1.135583025911358400418251384584930671458833e4L; 1154 enum T UF = -1.143276959615573793352782661133116431383730e4L; 1155 } 1156 else 1157 static assert(0, "Not implemented for this architecture"); 1158 1159 // Special cases. 1160 if (isNaN(x)) 1161 return x; 1162 if (x > OF) 1163 return real.infinity; 1164 if (x < UF) 1165 return 0.0; 1166 1167 // Express: e^^x = e^^g * 2^^n 1168 // = e^^g * e^^(n * LOG2E) 1169 // = e^^(g + n * LOG2E) 1170 T xx = floor((cast(T) LOG2E) * x + cast(T) 0.5); 1171 const int n = cast(int) xx; 1172 x -= xx * C1; 1173 x -= xx * C2; 1174 1175 static if (F.realFormat == RealFormat.ieeeSingle) 1176 { 1177 xx = x * x; 1178 x = poly(x, P) * xx + x + 1.0f; 1179 } 1180 else 1181 { 1182 // Rational approximation for exponential of the fractional part: 1183 // e^^x = 1 + 2x P(x^^2) / (Q(x^^2) - P(x^^2)) 1184 xx = x * x; 1185 const T px = x * poly(xx, P); 1186 x = px / (poly(xx, Q) - px); 1187 x = (cast(T) 1.0) + (cast(T) 2.0) * x; 1188 } 1189 1190 // Scale by power of 2. 1191 x = core.math.ldexp(x, n); 1192 1193 return x; 1194 } 1195 1196 @safe @nogc nothrow unittest 1197 { 1198 import std.math : floatTraits, RealFormat; 1199 import std.math.operations : NaN, feqrel, isClose; 1200 import std.math.constants : E; 1201 import std.math.traits : isIdentical; 1202 import std.math.algebraic : abs; 1203 1204 version (IeeeFlagsSupport) import std.math.hardware : IeeeFlags, resetIeeeFlags, ieeeFlags; 1205 version (FloatingPointControlSupport) 1206 { 1207 import std.math.hardware : FloatingPointControl; 1208 1209 FloatingPointControl ctrl; 1210 if (FloatingPointControl.hasExceptionTraps) 1211 ctrl.disableExceptions(FloatingPointControl.allExceptions); 1212 ctrl.rounding = FloatingPointControl.roundToNearest; 1213 } 1214 1215 static void testExp(T)() 1216 { 1217 enum realFormat = floatTraits!T.realFormat; 1218 static if (realFormat == RealFormat.ieeeQuadruple) 1219 { 1220 static immutable T[2][] exptestpoints = 1221 [ // x exp(x) 1222 [ 1.0L, E ], 1223 [ 0.5L, 0x1.a61298e1e069bc972dfefab6df34p+0L ], 1224 [ 3.0L, E*E*E ], 1225 [ 0x1.6p+13L, 0x1.6e509d45728655cdb4840542acb5p+16250L ], // near overflow 1226 [ 0x1.7p+13L, T.infinity ], // close overflow 1227 [ 0x1p+80L, T.infinity ], // far overflow 1228 [ T.infinity, T.infinity ], 1229 [-0x1.18p+13L, 0x1.5e4bf54b4807034ea97fef0059a6p-12927L ], // near underflow 1230 [-0x1.625p+13L, 0x1.a6bd68a39d11fec3a250cd97f524p-16358L ], // ditto 1231 [-0x1.62dafp+13L, 0x0.cb629e9813b80ed4d639e875be6cp-16382L ], // near underflow - subnormal 1232 [-0x1.6549p+13L, 0x0.0000000000000000000000000001p-16382L ], // ditto 1233 [-0x1.655p+13L, 0 ], // close underflow 1234 [-0x1p+30L, 0 ], // far underflow 1235 ]; 1236 } 1237 else static if (realFormat == RealFormat.ieeeExtended || 1238 realFormat == RealFormat.ieeeExtended53) 1239 { 1240 static immutable T[2][] exptestpoints = 1241 [ // x exp(x) 1242 [ 1.0L, E ], 1243 [ 0.5L, 0x1.a61298e1e069bc97p+0L ], 1244 [ 3.0L, E*E*E ], 1245 [ 0x1.1p+13L, 0x1.29aeffefc8ec645p+12557L ], // near overflow 1246 [ 0x1.7p+13L, T.infinity ], // close overflow 1247 [ 0x1p+80L, T.infinity ], // far overflow 1248 [ T.infinity, T.infinity ], 1249 [-0x1.18p+13L, 0x1.5e4bf54b4806db9p-12927L ], // near underflow 1250 [-0x1.625p+13L, 0x1.a6bd68a39d11f35cp-16358L ], // ditto 1251 [-0x1.62dafp+13L, 0x1.96c53d30277021dp-16383L ], // near underflow - subnormal 1252 [-0x1.643p+13L, 0x1p-16444L ], // ditto 1253 [-0x1.645p+13L, 0 ], // close underflow 1254 [-0x1p+30L, 0 ], // far underflow 1255 ]; 1256 } 1257 else static if (realFormat == RealFormat.ieeeDouble) 1258 { 1259 static immutable T[2][] exptestpoints = 1260 [ // x, exp(x) 1261 [ 1.0L, E ], 1262 [ 0.5L, 0x1.a61298e1e069cp+0L ], 1263 [ 3.0L, E*E*E ], 1264 [ 0x1.6p+9L, 0x1.93bf4ec282efbp+1015L ], // near overflow 1265 [ 0x1.7p+9L, T.infinity ], // close overflow 1266 [ 0x1p+80L, T.infinity ], // far overflow 1267 [ T.infinity, T.infinity ], 1268 [-0x1.6p+9L, 0x1.44a3824e5285fp-1016L ], // near underflow 1269 [-0x1.64p+9L, 0x0.06f84920bb2d4p-1022L ], // near underflow - subnormal 1270 [-0x1.743p+9L, 0x0.0000000000001p-1022L ], // ditto 1271 [-0x1.8p+9L, 0 ], // close underflow 1272 [-0x1p+30L, 0 ], // far underflow 1273 ]; 1274 } 1275 else static if (realFormat == RealFormat.ieeeSingle) 1276 { 1277 static immutable T[2][] exptestpoints = 1278 [ // x, exp(x) 1279 [ 1.0L, E ], 1280 [ 0.5L, 0x1.a61299p+0L ], 1281 [ 3.0L, E*E*E ], 1282 [ 0x1.62p+6L, 0x1.99b988p+127L ], // near overflow 1283 [ 0x1.7p+6L, T.infinity ], // close overflow 1284 [ 0x1p+80L, T.infinity ], // far overflow 1285 [ T.infinity, T.infinity ], 1286 [-0x1.5cp+6L, 0x1.666d0ep-126L ], // near underflow 1287 [-0x1.7p+6L, 0x0.026a42p-126L ], // near underflow - subnormal 1288 [-0x1.9cp+6L, 0x0.000002p-126L ], // ditto 1289 [-0x1.ap+6L, 0 ], // close underflow 1290 [-0x1p+30L, 0 ], // far underflow 1291 ]; 1292 } 1293 else 1294 static assert(0, "No exp() tests for real type!"); 1295 1296 const minEqualMantissaBits = T.mant_dig - 2; 1297 T x; 1298 version (IeeeFlagsSupport) IeeeFlags f; 1299 foreach (ref pair; exptestpoints) 1300 { 1301 version (IeeeFlagsSupport) resetIeeeFlags(); 1302 x = exp(pair[0]); 1303 //printf("exp(%La) = %La, should be %La\n", cast(real) pair[0], cast(real) x, cast(real) pair[1]); 1304 assert(feqrel(x, pair[1]) >= minEqualMantissaBits); 1305 } 1306 1307 // Ideally, exp(0) would not set the inexact flag. 1308 // Unfortunately, fldl2e sets it! 1309 // So it's not realistic to avoid setting it. 1310 assert(exp(cast(T) 0.0) == 1.0); 1311 1312 // NaN propagation. Doesn't set flags, bcos was already NaN. 1313 version (IeeeFlagsSupport) 1314 { 1315 resetIeeeFlags(); 1316 x = exp(T.nan); 1317 f = ieeeFlags; 1318 assert(isIdentical(abs(x), T.nan)); 1319 assert(f.flags == 0); 1320 1321 resetIeeeFlags(); 1322 x = exp(-T.nan); 1323 f = ieeeFlags; 1324 assert(isIdentical(abs(x), T.nan)); 1325 assert(f.flags == 0); 1326 } 1327 else 1328 { 1329 x = exp(T.nan); 1330 assert(isIdentical(abs(x), T.nan)); 1331 1332 x = exp(-T.nan); 1333 assert(isIdentical(abs(x), T.nan)); 1334 } 1335 1336 x = exp(NaN(0x123)); 1337 assert(isIdentical(x, NaN(0x123))); 1338 } 1339 1340 import std.meta : AliasSeq; 1341 foreach (T; AliasSeq!(real, double, float)) 1342 testExp!T(); 1343 1344 // High resolution test (verified against GNU MPFR/Mathematica). 1345 assert(exp(0.5L) == 0x1.A612_98E1_E069_BC97_2DFE_FAB6_DF34p+0L); 1346 1347 assert(isClose(exp(3.0L), E * E * E, real.sizeof > double.sizeof ? 1e-15 : 1e-14)); 1348 } 1349 1350 /** 1351 * Calculates the value of the natural logarithm base (e) 1352 * raised to the power of x, minus 1. 1353 * 1354 * For very small x, expm1(x) is more accurate 1355 * than exp(x)-1. 1356 * 1357 * $(TABLE_SV 1358 * $(TR $(TH x) $(TH e$(SUPERSCRIPT x)-1) ) 1359 * $(TR $(TD $(PLUSMN)0.0) $(TD $(PLUSMN)0.0) ) 1360 * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) ) 1361 * $(TR $(TD -$(INFIN)) $(TD -1.0) ) 1362 * $(TR $(TD $(NAN)) $(TD $(NAN)) ) 1363 * ) 1364 */ 1365 pragma(inline, true) 1366 real expm1(real x) @trusted pure nothrow @nogc // TODO: @safe 1367 { 1368 version (InlineAsm_X87) 1369 { 1370 if (!__ctfe) 1371 return expm1Asm(x); 1372 } 1373 return expm1Impl(x); 1374 } 1375 1376 /// ditto 1377 pragma(inline, true) 1378 double expm1(double x) @safe pure nothrow @nogc 1379 { 1380 return __ctfe ? cast(double) expm1(cast(real) x) : expm1Impl(x); 1381 } 1382 1383 /// ditto 1384 pragma(inline, true) 1385 float expm1(float x) @safe pure nothrow @nogc 1386 { 1387 // no single-precision version in Cephes => use double precision 1388 return __ctfe ? cast(float) expm1(cast(real) x) : cast(float) expm1Impl(cast(double) x); 1389 } 1390 1391 /// 1392 @safe unittest 1393 { 1394 import std.math.traits : isIdentical; 1395 import std.math.operations : feqrel; 1396 1397 assert(isIdentical(expm1(0.0), 0.0)); 1398 assert(expm1(1.0).feqrel(1.71828) > 16); 1399 assert(expm1(2.0).feqrel(6.3890) > 16); 1400 } 1401 1402 version (InlineAsm_X87) 1403 private real expm1Asm(real x) @trusted pure nothrow @nogc 1404 { 1405 version (X86) 1406 { 1407 enum PARAMSIZE = (real.sizeof+3)&(0xFFFF_FFFC); // always a multiple of 4 1408 asm pure nothrow @nogc 1409 { 1410 /* expm1() for x87 80-bit reals, IEEE754-2008 conformant. 1411 * Author: Don Clugston. 1412 * 1413 * expm1(x) = 2^^(rndint(y))* 2^^(y-rndint(y)) - 1 where y = LN2*x. 1414 * = 2rndy * 2ym1 + 2rndy - 1, where 2rndy = 2^^(rndint(y)) 1415 * and 2ym1 = (2^^(y-rndint(y))-1). 1416 * If 2rndy < 0.5*real.epsilon, result is -1. 1417 * Implementation is otherwise the same as for exp2() 1418 */ 1419 naked; 1420 fld real ptr [ESP+4] ; // x 1421 mov AX, [ESP+4+8]; // AX = exponent and sign 1422 sub ESP, 12+8; // Create scratch space on the stack 1423 // [ESP,ESP+2] = scratchint 1424 // [ESP+4..+6, +8..+10, +10] = scratchreal 1425 // set scratchreal mantissa = 1.0 1426 mov dword ptr [ESP+8], 0; 1427 mov dword ptr [ESP+8+4], 0x80000000; 1428 and AX, 0x7FFF; // drop sign bit 1429 cmp AX, 0x401D; // avoid InvalidException in fist 1430 jae L_extreme; 1431 fldl2e; 1432 fmulp ST(1), ST; // y = x*log2(e) 1433 fist dword ptr [ESP]; // scratchint = rndint(y) 1434 fisub dword ptr [ESP]; // y - rndint(y) 1435 // and now set scratchreal exponent 1436 mov EAX, [ESP]; 1437 add EAX, 0x3fff; 1438 jle short L_largenegative; 1439 cmp EAX,0x8000; 1440 jge short L_largepositive; 1441 mov [ESP+8+8],AX; 1442 f2xm1; // 2ym1 = 2^^(y-rndint(y)) -1 1443 fld real ptr [ESP+8] ; // 2rndy = 2^^rndint(y) 1444 fmul ST(1), ST; // ST=2rndy, ST(1)=2rndy*2ym1 1445 fld1; 1446 fsubp ST(1), ST; // ST = 2rndy-1, ST(1) = 2rndy * 2ym1 - 1 1447 faddp ST(1), ST; // ST = 2rndy * 2ym1 + 2rndy - 1 1448 add ESP,12+8; 1449 ret PARAMSIZE; 1450 1451 L_extreme: // Extreme exponent. X is very large positive, very 1452 // large negative, infinity, or NaN. 1453 fxam; 1454 fstsw AX; 1455 test AX, 0x0400; // NaN_or_zero, but we already know x != 0 1456 jz L_was_nan; // if x is NaN, returns x 1457 test AX, 0x0200; 1458 jnz L_largenegative; 1459 L_largepositive: 1460 // Set scratchreal = real.max. 1461 // squaring it will create infinity, and set overflow flag. 1462 mov word ptr [ESP+8+8], 0x7FFE; 1463 fstp ST(0); 1464 fld real ptr [ESP+8]; // load scratchreal 1465 fmul ST(0), ST; // square it, to create havoc! 1466 L_was_nan: 1467 add ESP,12+8; 1468 ret PARAMSIZE; 1469 L_largenegative: 1470 fstp ST(0); 1471 fld1; 1472 fchs; // return -1. Underflow flag is not set. 1473 add ESP,12+8; 1474 ret PARAMSIZE; 1475 } 1476 } 1477 else version (X86_64) 1478 { 1479 asm pure nothrow @nogc 1480 { 1481 naked; 1482 } 1483 version (Win64) 1484 { 1485 asm pure nothrow @nogc 1486 { 1487 fld real ptr [RCX]; // x 1488 mov AX,[RCX+8]; // AX = exponent and sign 1489 } 1490 } 1491 else 1492 { 1493 asm pure nothrow @nogc 1494 { 1495 fld real ptr [RSP+8]; // x 1496 mov AX,[RSP+8+8]; // AX = exponent and sign 1497 } 1498 } 1499 asm pure nothrow @nogc 1500 { 1501 /* expm1() for x87 80-bit reals, IEEE754-2008 conformant. 1502 * Author: Don Clugston. 1503 * 1504 * expm1(x) = 2^(rndint(y))* 2^(y-rndint(y)) - 1 where y = LN2*x. 1505 * = 2rndy * 2ym1 + 2rndy - 1, where 2rndy = 2^(rndint(y)) 1506 * and 2ym1 = (2^(y-rndint(y))-1). 1507 * If 2rndy < 0.5*real.epsilon, result is -1. 1508 * Implementation is otherwise the same as for exp2() 1509 */ 1510 sub RSP, 24; // Create scratch space on the stack 1511 // [RSP,RSP+2] = scratchint 1512 // [RSP+4..+6, +8..+10, +10] = scratchreal 1513 // set scratchreal mantissa = 1.0 1514 mov dword ptr [RSP+8], 0; 1515 mov dword ptr [RSP+8+4], 0x80000000; 1516 and AX, 0x7FFF; // drop sign bit 1517 cmp AX, 0x401D; // avoid InvalidException in fist 1518 jae L_extreme; 1519 fldl2e; 1520 fmul ; // y = x*log2(e) 1521 fist dword ptr [RSP]; // scratchint = rndint(y) 1522 fisub dword ptr [RSP]; // y - rndint(y) 1523 // and now set scratchreal exponent 1524 mov EAX, [RSP]; 1525 add EAX, 0x3fff; 1526 jle short L_largenegative; 1527 cmp EAX,0x8000; 1528 jge short L_largepositive; 1529 mov [RSP+8+8],AX; 1530 f2xm1; // 2^(y-rndint(y)) -1 1531 fld real ptr [RSP+8] ; // 2^rndint(y) 1532 fmul ST(1), ST; 1533 fld1; 1534 fsubp ST(1), ST; 1535 fadd; 1536 add RSP,24; 1537 ret; 1538 1539 L_extreme: // Extreme exponent. X is very large positive, very 1540 // large negative, infinity, or NaN. 1541 fxam; 1542 fstsw AX; 1543 test AX, 0x0400; // NaN_or_zero, but we already know x != 0 1544 jz L_was_nan; // if x is NaN, returns x 1545 test AX, 0x0200; 1546 jnz L_largenegative; 1547 L_largepositive: 1548 // Set scratchreal = real.max. 1549 // squaring it will create infinity, and set overflow flag. 1550 mov word ptr [RSP+8+8], 0x7FFE; 1551 fstp ST(0); 1552 fld real ptr [RSP+8]; // load scratchreal 1553 fmul ST(0), ST; // square it, to create havoc! 1554 L_was_nan: 1555 add RSP,24; 1556 ret; 1557 1558 L_largenegative: 1559 fstp ST(0); 1560 fld1; 1561 fchs; // return -1. Underflow flag is not set. 1562 add RSP,24; 1563 ret; 1564 } 1565 } 1566 else 1567 static assert(0); 1568 } 1569 1570 private T expm1Impl(T)(T x) @safe pure nothrow @nogc 1571 { 1572 import std.math : floatTraits, RealFormat; 1573 import std.math.rounding : floor; 1574 import std.math.algebraic : poly; 1575 import std.math.constants : LN2; 1576 1577 // Coefficients for exp(x) - 1 and overflow/underflow limits. 1578 enum realFormat = floatTraits!T.realFormat; 1579 static if (realFormat == RealFormat.ieeeQuadruple) 1580 { 1581 static immutable T[8] P = [ 1582 2.943520915569954073888921213330863757240E8L, 1583 -5.722847283900608941516165725053359168840E7L, 1584 8.944630806357575461578107295909719817253E6L, 1585 -7.212432713558031519943281748462837065308E5L, 1586 4.578962475841642634225390068461943438441E4L, 1587 -1.716772506388927649032068540558788106762E3L, 1588 4.401308817383362136048032038528753151144E1L, 1589 -4.888737542888633647784737721812546636240E-1L 1590 ]; 1591 1592 static immutable T[9] Q = [ 1593 1.766112549341972444333352727998584753865E9L, 1594 -7.848989743695296475743081255027098295771E8L, 1595 1.615869009634292424463780387327037251069E8L, 1596 -2.019684072836541751428967854947019415698E7L, 1597 1.682912729190313538934190635536631941751E6L, 1598 -9.615511549171441430850103489315371768998E4L, 1599 3.697714952261803935521187272204485251835E3L, 1600 -8.802340681794263968892934703309274564037E1L, 1601 1.0 1602 ]; 1603 1604 enum T OF = 1.1356523406294143949491931077970764891253E4L; 1605 enum T UF = -1.143276959615573793352782661133116431383730e4L; 1606 } 1607 else static if (realFormat == RealFormat.ieeeExtended) 1608 { 1609 static immutable T[5] P = [ 1610 -1.586135578666346600772998894928250240826E4L, 1611 2.642771505685952966904660652518429479531E3L, 1612 -3.423199068835684263987132888286791620673E2L, 1613 1.800826371455042224581246202420972737840E1L, 1614 -5.238523121205561042771939008061958820811E-1L, 1615 ]; 1616 static immutable T[6] Q = [ 1617 -9.516813471998079611319047060563358064497E4L, 1618 3.964866271411091674556850458227710004570E4L, 1619 -7.207678383830091850230366618190187434796E3L, 1620 7.206038318724600171970199625081491823079E2L, 1621 -4.002027679107076077238836622982900945173E1L, 1622 1.0 1623 ]; 1624 1625 enum T OF = 1.1356523406294143949492E4L; 1626 enum T UF = -4.5054566736396445112120088E1L; 1627 } 1628 else static if (realFormat == RealFormat.ieeeDouble) 1629 { 1630 static immutable T[3] P = [ 1631 9.9999999999999999991025E-1, 1632 3.0299440770744196129956E-2, 1633 1.2617719307481059087798E-4, 1634 ]; 1635 static immutable T[4] Q = [ 1636 2.0000000000000000000897E0, 1637 2.2726554820815502876593E-1, 1638 2.5244834034968410419224E-3, 1639 3.0019850513866445504159E-6, 1640 ]; 1641 } 1642 else 1643 static assert(0, "no coefficients for expm1()"); 1644 1645 static if (realFormat == RealFormat.ieeeDouble) // special case for double precision 1646 { 1647 if (x < -0.5 || x > 0.5) 1648 return exp(x) - 1.0; 1649 if (x == 0.0) 1650 return x; 1651 1652 const T xx = x * x; 1653 x = x * poly(xx, P); 1654 x = x / (poly(xx, Q) - x); 1655 return x + x; 1656 } 1657 else 1658 { 1659 // C1 + C2 = LN2. 1660 enum T C1 = 6.9314575195312500000000E-1L; 1661 enum T C2 = 1.428606820309417232121458176568075500134E-6L; 1662 1663 // Special cases. 1664 if (x > OF) 1665 return real.infinity; 1666 if (x == cast(T) 0.0) 1667 return x; 1668 if (x < UF) 1669 return -1.0; 1670 1671 // Express x = LN2 (n + remainder), remainder not exceeding 1/2. 1672 int n = cast(int) floor((cast(T) 0.5) + x / cast(T) LN2); 1673 x -= n * C1; 1674 x -= n * C2; 1675 1676 // Rational approximation: 1677 // exp(x) - 1 = x + 0.5 x^^2 + x^^3 P(x) / Q(x) 1678 T px = x * poly(x, P); 1679 T qx = poly(x, Q); 1680 const T xx = x * x; 1681 qx = x + ((cast(T) 0.5) * xx + xx * px / qx); 1682 1683 // We have qx = exp(remainder LN2) - 1, so: 1684 // exp(x) - 1 = 2^^n (qx + 1) - 1 = 2^^n qx + 2^^n - 1. 1685 px = core.math.ldexp(cast(T) 1.0, n); 1686 x = px * qx + (px - cast(T) 1.0); 1687 1688 return x; 1689 } 1690 } 1691 1692 @safe @nogc nothrow unittest 1693 { 1694 import std.math.traits : isNaN; 1695 import std.math.operations : isClose, CommonDefaultFor; 1696 1697 static void testExpm1(T)() 1698 { 1699 // NaN 1700 assert(isNaN(expm1(cast(T) T.nan))); 1701 1702 static immutable T[] xs = [ -2, -0.75, -0.3, 0.0, 0.1, 0.2, 0.5, 1.0 ]; 1703 foreach (x; xs) 1704 { 1705 const T e = expm1(x); 1706 const T r = exp(x) - 1; 1707 1708 //printf("expm1(%Lg) = %Lg, should approximately be %Lg\n", cast(real) x, cast(real) e, cast(real) r); 1709 assert(isClose(r, e, CommonDefaultFor!(T,T), CommonDefaultFor!(T,T))); 1710 } 1711 } 1712 1713 import std.meta : AliasSeq; 1714 foreach (T; AliasSeq!(real, double)) 1715 testExpm1!T(); 1716 } 1717 1718 /** 1719 * Calculates 2$(SUPERSCRIPT x). 1720 * 1721 * $(TABLE_SV 1722 * $(TR $(TH x) $(TH exp2(x)) ) 1723 * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) ) 1724 * $(TR $(TD -$(INFIN)) $(TD +0.0) ) 1725 * $(TR $(TD $(NAN)) $(TD $(NAN)) ) 1726 * ) 1727 */ 1728 version (none) // LDC FIXME: Use of this LLVM intrinsic causes a unit test failure 1729 { 1730 pragma(inline, true): 1731 real exp2(real x) @safe pure nothrow @nogc { return llvm_exp2(x); } 1732 ///ditto 1733 double exp2(double x) @safe pure nothrow @nogc { return llvm_exp2(x); } 1734 ///ditto 1735 float exp2(float x) @safe pure nothrow @nogc { return llvm_exp2(x); } 1736 } 1737 else 1738 { 1739 1740 pragma(inline, true) 1741 real exp2(real x) @nogc @trusted pure nothrow // TODO: @safe 1742 { 1743 version (InlineAsm_X87) 1744 { 1745 if (!__ctfe) 1746 return exp2Asm(x); 1747 } 1748 return exp2Impl(x); 1749 } 1750 1751 /// ditto 1752 pragma(inline, true) 1753 double exp2(double x) @nogc @safe pure nothrow { return __ctfe ? cast(double) exp2(cast(real) x) : exp2Impl(x); } 1754 1755 /// ditto 1756 pragma(inline, true) 1757 float exp2(float x) @nogc @safe pure nothrow { return __ctfe ? cast(float) exp2(cast(real) x) : exp2Impl(x); } 1758 1759 } // !none 1760 1761 /// 1762 @safe unittest 1763 { 1764 import std.math.traits : isIdentical; 1765 import std.math.operations : feqrel; 1766 1767 assert(isIdentical(exp2(0.0), 1.0)); 1768 assert(exp2(2.0).feqrel(4.0) > 16); 1769 assert(exp2(8.0).feqrel(256.0) > 16); 1770 } 1771 1772 @safe unittest 1773 { 1774 version (CRuntime_Microsoft) {} else // aexp2/exp2f/exp2l not implemented 1775 { 1776 assert( core.stdc.math.exp2f(0.0f) == 1 ); 1777 assert( core.stdc.math.exp2 (0.0) == 1 ); 1778 assert( core.stdc.math.exp2l(0.0L) == 1 ); 1779 } 1780 } 1781 1782 version (InlineAsm_X87) 1783 private real exp2Asm(real x) @nogc @trusted pure nothrow 1784 { 1785 version (X86) 1786 { 1787 enum PARAMSIZE = (real.sizeof+3)&(0xFFFF_FFFC); // always a multiple of 4 1788 1789 asm pure nothrow @nogc 1790 { 1791 /* exp2() for x87 80-bit reals, IEEE754-2008 conformant. 1792 * Author: Don Clugston. 1793 * 1794 * exp2(x) = 2^^(rndint(x))* 2^^(y-rndint(x)) 1795 * The trick for high performance is to avoid the fscale(28cycles on core2), 1796 * frndint(19 cycles), leaving f2xm1(19 cycles) as the only slow instruction. 1797 * 1798 * We can do frndint by using fist. BUT we can't use it for huge numbers, 1799 * because it will set the Invalid Operation flag if overflow or NaN occurs. 1800 * Fortunately, whenever this happens the result would be zero or infinity. 1801 * 1802 * We can perform fscale by directly poking into the exponent. BUT this doesn't 1803 * work for the (very rare) cases where the result is subnormal. So we fall back 1804 * to the slow method in that case. 1805 */ 1806 naked; 1807 fld real ptr [ESP+4] ; // x 1808 mov AX, [ESP+4+8]; // AX = exponent and sign 1809 sub ESP, 12+8; // Create scratch space on the stack 1810 // [ESP,ESP+2] = scratchint 1811 // [ESP+4..+6, +8..+10, +10] = scratchreal 1812 // set scratchreal mantissa = 1.0 1813 mov dword ptr [ESP+8], 0; 1814 mov dword ptr [ESP+8+4], 0x80000000; 1815 and AX, 0x7FFF; // drop sign bit 1816 cmp AX, 0x401D; // avoid InvalidException in fist 1817 jae L_extreme; 1818 fist dword ptr [ESP]; // scratchint = rndint(x) 1819 fisub dword ptr [ESP]; // x - rndint(x) 1820 // and now set scratchreal exponent 1821 mov EAX, [ESP]; 1822 add EAX, 0x3fff; 1823 jle short L_subnormal; 1824 cmp EAX,0x8000; 1825 jge short L_overflow; 1826 mov [ESP+8+8],AX; 1827 L_normal: 1828 f2xm1; 1829 fld1; 1830 faddp ST(1), ST; // 2^^(x-rndint(x)) 1831 fld real ptr [ESP+8] ; // 2^^rndint(x) 1832 add ESP,12+8; 1833 fmulp ST(1), ST; 1834 ret PARAMSIZE; 1835 1836 L_subnormal: 1837 // Result will be subnormal. 1838 // In this rare case, the simple poking method doesn't work. 1839 // The speed doesn't matter, so use the slow fscale method. 1840 fild dword ptr [ESP]; // scratchint 1841 fld1; 1842 fscale; 1843 fstp real ptr [ESP+8]; // scratchreal = 2^^scratchint 1844 fstp ST(0); // drop scratchint 1845 jmp L_normal; 1846 1847 L_extreme: // Extreme exponent. X is very large positive, very 1848 // large negative, infinity, or NaN. 1849 fxam; 1850 fstsw AX; 1851 test AX, 0x0400; // NaN_or_zero, but we already know x != 0 1852 jz L_was_nan; // if x is NaN, returns x 1853 // set scratchreal = real.min_normal 1854 // squaring it will return 0, setting underflow flag 1855 mov word ptr [ESP+8+8], 1; 1856 test AX, 0x0200; 1857 jnz L_waslargenegative; 1858 L_overflow: 1859 // Set scratchreal = real.max. 1860 // squaring it will create infinity, and set overflow flag. 1861 mov word ptr [ESP+8+8], 0x7FFE; 1862 L_waslargenegative: 1863 fstp ST(0); 1864 fld real ptr [ESP+8]; // load scratchreal 1865 fmul ST(0), ST; // square it, to create havoc! 1866 L_was_nan: 1867 add ESP,12+8; 1868 ret PARAMSIZE; 1869 } 1870 } 1871 else version (X86_64) 1872 { 1873 asm pure nothrow @nogc 1874 { 1875 naked; 1876 } 1877 version (Win64) 1878 { 1879 asm pure nothrow @nogc 1880 { 1881 fld real ptr [RCX]; // x 1882 mov AX,[RCX+8]; // AX = exponent and sign 1883 } 1884 } 1885 else 1886 { 1887 asm pure nothrow @nogc 1888 { 1889 fld real ptr [RSP+8]; // x 1890 mov AX,[RSP+8+8]; // AX = exponent and sign 1891 } 1892 } 1893 asm pure nothrow @nogc 1894 { 1895 /* exp2() for x87 80-bit reals, IEEE754-2008 conformant. 1896 * Author: Don Clugston. 1897 * 1898 * exp2(x) = 2^(rndint(x))* 2^(y-rndint(x)) 1899 * The trick for high performance is to avoid the fscale(28cycles on core2), 1900 * frndint(19 cycles), leaving f2xm1(19 cycles) as the only slow instruction. 1901 * 1902 * We can do frndint by using fist. BUT we can't use it for huge numbers, 1903 * because it will set the Invalid Operation flag is overflow or NaN occurs. 1904 * Fortunately, whenever this happens the result would be zero or infinity. 1905 * 1906 * We can perform fscale by directly poking into the exponent. BUT this doesn't 1907 * work for the (very rare) cases where the result is subnormal. So we fall back 1908 * to the slow method in that case. 1909 */ 1910 sub RSP, 24; // Create scratch space on the stack 1911 // [RSP,RSP+2] = scratchint 1912 // [RSP+4..+6, +8..+10, +10] = scratchreal 1913 // set scratchreal mantissa = 1.0 1914 mov dword ptr [RSP+8], 0; 1915 mov dword ptr [RSP+8+4], 0x80000000; 1916 and AX, 0x7FFF; // drop sign bit 1917 cmp AX, 0x401D; // avoid InvalidException in fist 1918 jae L_extreme; 1919 fist dword ptr [RSP]; // scratchint = rndint(x) 1920 fisub dword ptr [RSP]; // x - rndint(x) 1921 // and now set scratchreal exponent 1922 mov EAX, [RSP]; 1923 add EAX, 0x3fff; 1924 jle short L_subnormal; 1925 cmp EAX,0x8000; 1926 jge short L_overflow; 1927 mov [RSP+8+8],AX; 1928 L_normal: 1929 f2xm1; 1930 fld1; 1931 fadd; // 2^(x-rndint(x)) 1932 fld real ptr [RSP+8] ; // 2^rndint(x) 1933 add RSP,24; 1934 fmulp ST(1), ST; 1935 ret; 1936 1937 L_subnormal: 1938 // Result will be subnormal. 1939 // In this rare case, the simple poking method doesn't work. 1940 // The speed doesn't matter, so use the slow fscale method. 1941 fild dword ptr [RSP]; // scratchint 1942 fld1; 1943 fscale; 1944 fstp real ptr [RSP+8]; // scratchreal = 2^scratchint 1945 fstp ST(0); // drop scratchint 1946 jmp L_normal; 1947 1948 L_extreme: // Extreme exponent. X is very large positive, very 1949 // large negative, infinity, or NaN. 1950 fxam; 1951 fstsw AX; 1952 test AX, 0x0400; // NaN_or_zero, but we already know x != 0 1953 jz L_was_nan; // if x is NaN, returns x 1954 // set scratchreal = real.min 1955 // squaring it will return 0, setting underflow flag 1956 mov word ptr [RSP+8+8], 1; 1957 test AX, 0x0200; 1958 jnz L_waslargenegative; 1959 L_overflow: 1960 // Set scratchreal = real.max. 1961 // squaring it will create infinity, and set overflow flag. 1962 mov word ptr [RSP+8+8], 0x7FFE; 1963 L_waslargenegative: 1964 fstp ST(0); 1965 fld real ptr [RSP+8]; // load scratchreal 1966 fmul ST(0), ST; // square it, to create havoc! 1967 L_was_nan: 1968 add RSP,24; 1969 ret; 1970 } 1971 } 1972 else 1973 static assert(0); 1974 } 1975 1976 private T exp2Impl(T)(T x) @nogc @safe pure nothrow 1977 { 1978 import std.math : floatTraits, RealFormat; 1979 import std.math.traits : isNaN; 1980 import std.math.rounding : floor; 1981 import std.math.algebraic : poly; 1982 1983 // Coefficients for exp2(x) 1984 enum realFormat = floatTraits!T.realFormat; 1985 static if (realFormat == RealFormat.ieeeQuadruple) 1986 { 1987 static immutable T[5] P = [ 1988 9.079594442980146270952372234833529694788E12L, 1989 1.530625323728429161131811299626419117557E11L, 1990 5.677513871931844661829755443994214173883E8L, 1991 6.185032670011643762127954396427045467506E5L, 1992 1.587171580015525194694938306936721666031E2L 1993 ]; 1994 1995 static immutable T[6] Q = [ 1996 2.619817175234089411411070339065679229869E13L, 1997 1.490560994263653042761789432690793026977E12L, 1998 1.092141473886177435056423606755843616331E10L, 1999 2.186249607051644894762167991800811827835E7L, 2000 1.236602014442099053716561665053645270207E4L, 2001 1.0 2002 ]; 2003 } 2004 else static if (realFormat == RealFormat.ieeeExtended) 2005 { 2006 static immutable T[3] P = [ 2007 2.0803843631901852422887E6L, 2008 3.0286971917562792508623E4L, 2009 6.0614853552242266094567E1L, 2010 ]; 2011 static immutable T[4] Q = [ 2012 6.0027204078348487957118E6L, 2013 3.2772515434906797273099E5L, 2014 1.7492876999891839021063E3L, 2015 1.0000000000000000000000E0L, 2016 ]; 2017 } 2018 else static if (realFormat == RealFormat.ieeeDouble) 2019 { 2020 static immutable T[3] P = [ 2021 1.51390680115615096133E3L, 2022 2.02020656693165307700E1L, 2023 2.30933477057345225087E-2L, 2024 ]; 2025 static immutable T[3] Q = [ 2026 4.36821166879210612817E3L, 2027 2.33184211722314911771E2L, 2028 1.00000000000000000000E0L, 2029 ]; 2030 } 2031 else static if (realFormat == RealFormat.ieeeSingle) 2032 { 2033 static immutable T[6] P = [ 2034 6.931472028550421E-001L, 2035 2.402264791363012E-001L, 2036 5.550332471162809E-002L, 2037 9.618437357674640E-003L, 2038 1.339887440266574E-003L, 2039 1.535336188319500E-004L, 2040 ]; 2041 } 2042 else 2043 static assert(0, "no coefficients for exp2()"); 2044 2045 // Overflow and Underflow limits. 2046 enum T OF = T.max_exp; 2047 enum T UF = T.min_exp - 1; 2048 2049 // Special cases. 2050 if (isNaN(x)) 2051 return x; 2052 if (x > OF) 2053 return real.infinity; 2054 if (x < UF) 2055 return 0.0; 2056 2057 static if (realFormat == RealFormat.ieeeSingle) // special case for single precision 2058 { 2059 // The following is necessary because range reduction blows up. 2060 if (x == 0.0f) 2061 return 1.0f; 2062 2063 // Separate into integer and fractional parts. 2064 const T i = floor(x); 2065 int n = cast(int) i; 2066 x -= i; 2067 if (x > 0.5f) 2068 { 2069 n += 1; 2070 x -= 1.0f; 2071 } 2072 2073 // Rational approximation: 2074 // exp2(x) = 1.0 + x P(x) 2075 x = 1.0f + x * poly(x, P); 2076 } 2077 else 2078 { 2079 // Separate into integer and fractional parts. 2080 const T i = floor(x + cast(T) 0.5); 2081 int n = cast(int) i; 2082 x -= i; 2083 2084 // Rational approximation: 2085 // exp2(x) = 1.0 + 2x P(x^^2) / (Q(x^^2) - P(x^^2)) 2086 const T xx = x * x; 2087 const T px = x * poly(xx, P); 2088 x = px / (poly(xx, Q) - px); 2089 x = (cast(T) 1.0) + (cast(T) 2.0) * x; 2090 } 2091 2092 // Scale by power of 2. 2093 x = core.math.ldexp(x, n); 2094 2095 return x; 2096 } 2097 2098 @safe @nogc nothrow unittest 2099 { 2100 import std.math.operations : feqrel, NaN, isClose; 2101 import std.math.traits : isIdentical; 2102 import std.math.constants : SQRT2; 2103 2104 assert(feqrel(exp2(0.5L), SQRT2) >= real.mant_dig -1); 2105 assert(exp2(8.0L) == 256.0); 2106 assert(exp2(-9.0L)== 1.0L/512.0); 2107 2108 static void testExp2(T)() 2109 { 2110 // NaN 2111 const T specialNaN = NaN(0x0123L); 2112 assert(isIdentical(exp2(specialNaN), specialNaN)); 2113 2114 // over-/underflow 2115 enum T OF = T.max_exp; 2116 enum T UF = T.min_exp - T.mant_dig; 2117 assert(isIdentical(exp2(OF + 1), cast(T) T.infinity)); 2118 assert(isIdentical(exp2(UF - 1), cast(T) 0.0)); 2119 2120 static immutable T[2][] vals = 2121 [ 2122 // x, exp2(x) 2123 [ 0.0, 1.0 ], 2124 [ -0.0, 1.0 ], 2125 [ 0.5, SQRT2 ], 2126 [ 8.0, 256.0 ], 2127 [ -9.0, 1.0 / 512 ], 2128 ]; 2129 2130 foreach (ref val; vals) 2131 { 2132 const T x = val[0]; 2133 const T r = val[1]; 2134 const T e = exp2(x); 2135 2136 //printf("exp2(%Lg) = %Lg, should be %Lg\n", cast(real) x, cast(real) e, cast(real) r); 2137 assert(isClose(r, e)); 2138 } 2139 } 2140 2141 import std.meta : AliasSeq; 2142 foreach (T; AliasSeq!(real, double, float)) 2143 testExp2!T(); 2144 } 2145 2146 /********************************************************************* 2147 * Separate floating point value into significand and exponent. 2148 * 2149 * Returns: 2150 * Calculate and return $(I x) and $(I exp) such that 2151 * value =$(I x)*2$(SUPERSCRIPT exp) and 2152 * .5 $(LT)= |$(I x)| $(LT) 1.0 2153 * 2154 * $(I x) has same sign as value. 2155 * 2156 * $(TABLE_SV 2157 * $(TR $(TH value) $(TH returns) $(TH exp)) 2158 * $(TR $(TD $(PLUSMN)0.0) $(TD $(PLUSMN)0.0) $(TD 0)) 2159 * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) $(TD int.max)) 2160 * $(TR $(TD -$(INFIN)) $(TD -$(INFIN)) $(TD int.min)) 2161 * $(TR $(TD $(PLUSMN)$(NAN)) $(TD $(PLUSMN)$(NAN)) $(TD int.min)) 2162 * ) 2163 */ 2164 T frexp(T)(const T value, out int exp) @trusted pure nothrow @nogc 2165 if (isFloatingPoint!T) 2166 { 2167 import std.math : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB; 2168 import std.math.traits : isSubnormal; 2169 2170 if (__ctfe) 2171 { 2172 // Handle special cases. 2173 if (value == 0) { exp = 0; return value; } 2174 if (value == T.infinity) { exp = int.max; return value; } 2175 if (value == -T.infinity || value != value) { exp = int.min; return value; } 2176 // Handle ordinary cases. 2177 // In CTFE there is no performance advantage for having separate 2178 // paths for different floating point types. 2179 T absValue = value < 0 ? -value : value; 2180 int expCount; 2181 static if (T.mant_dig > double.mant_dig) 2182 { 2183 for (; absValue >= 0x1.0p+1024L; absValue *= 0x1.0p-1024L) 2184 expCount += 1024; 2185 for (; absValue < 0x1.0p-1021L; absValue *= 0x1.0p+1021L) 2186 expCount -= 1021; 2187 } 2188 const double dval = cast(double) absValue; 2189 int dexp = cast(int) (((*cast(const long*) &dval) >>> 52) & 0x7FF) + double.min_exp - 2; 2190 dexp++; 2191 expCount += dexp; 2192 absValue *= 2.0 ^^ -dexp; 2193 // If the original value was subnormal or if it was a real 2194 // then absValue can still be outside the [0.5, 1.0) range. 2195 if (absValue < 0.5) 2196 { 2197 assert(T.mant_dig > double.mant_dig || isSubnormal(value)); 2198 do 2199 { 2200 absValue += absValue; 2201 expCount--; 2202 } while (absValue < 0.5); 2203 } 2204 else 2205 { 2206 assert(absValue < 1 || T.mant_dig > double.mant_dig); 2207 for (; absValue >= 1; absValue *= T(0.5)) 2208 expCount++; 2209 } 2210 exp = expCount; 2211 return value < 0 ? -absValue : absValue; 2212 } 2213 2214 Unqual!T vf = value; 2215 ushort* vu = cast(ushort*)&vf; 2216 static if (is(immutable T == immutable float)) 2217 int* vi = cast(int*)&vf; 2218 else 2219 long* vl = cast(long*)&vf; 2220 int ex; 2221 alias F = floatTraits!T; 2222 2223 ex = vu[F.EXPPOS_SHORT] & F.EXPMASK; 2224 static if (F.realFormat == RealFormat.ieeeExtended || 2225 F.realFormat == RealFormat.ieeeExtended53) 2226 { 2227 if (ex) 2228 { // If exponent is non-zero 2229 if (ex == F.EXPMASK) // infinity or NaN 2230 { 2231 if (*vl & 0x7FFF_FFFF_FFFF_FFFF) // NaN 2232 { 2233 *vl |= 0xC000_0000_0000_0000; // convert NaNS to NaNQ 2234 exp = int.min; 2235 } 2236 else if (vu[F.EXPPOS_SHORT] & 0x8000) // negative infinity 2237 exp = int.min; 2238 else // positive infinity 2239 exp = int.max; 2240 2241 } 2242 else 2243 { 2244 exp = ex - F.EXPBIAS; 2245 vu[F.EXPPOS_SHORT] = (0x8000 & vu[F.EXPPOS_SHORT]) | 0x3FFE; 2246 } 2247 } 2248 else if (!*vl) 2249 { 2250 // vf is +-0.0 2251 exp = 0; 2252 } 2253 else 2254 { 2255 // subnormal 2256 2257 vf *= F.RECIP_EPSILON; 2258 ex = vu[F.EXPPOS_SHORT] & F.EXPMASK; 2259 exp = ex - F.EXPBIAS - T.mant_dig + 1; 2260 vu[F.EXPPOS_SHORT] = ((-1 - F.EXPMASK) & vu[F.EXPPOS_SHORT]) | 0x3FFE; 2261 } 2262 return vf; 2263 } 2264 else static if (F.realFormat == RealFormat.ieeeQuadruple) 2265 { 2266 if (ex) // If exponent is non-zero 2267 { 2268 if (ex == F.EXPMASK) 2269 { 2270 // infinity or NaN 2271 if (vl[MANTISSA_LSB] | 2272 (vl[MANTISSA_MSB] & 0x0000_FFFF_FFFF_FFFF)) // NaN 2273 { 2274 // convert NaNS to NaNQ 2275 vl[MANTISSA_MSB] |= 0x0000_8000_0000_0000; 2276 exp = int.min; 2277 } 2278 else if (vu[F.EXPPOS_SHORT] & 0x8000) // negative infinity 2279 exp = int.min; 2280 else // positive infinity 2281 exp = int.max; 2282 } 2283 else 2284 { 2285 exp = ex - F.EXPBIAS; 2286 vu[F.EXPPOS_SHORT] = F.EXPBIAS | (0x8000 & vu[F.EXPPOS_SHORT]); 2287 } 2288 } 2289 else if ((vl[MANTISSA_LSB] | 2290 (vl[MANTISSA_MSB] & 0x0000_FFFF_FFFF_FFFF)) == 0) 2291 { 2292 // vf is +-0.0 2293 exp = 0; 2294 } 2295 else 2296 { 2297 // subnormal 2298 vf *= F.RECIP_EPSILON; 2299 ex = vu[F.EXPPOS_SHORT] & F.EXPMASK; 2300 exp = ex - F.EXPBIAS - T.mant_dig + 1; 2301 vu[F.EXPPOS_SHORT] = F.EXPBIAS | (0x8000 & vu[F.EXPPOS_SHORT]); 2302 } 2303 return vf; 2304 } 2305 else static if (F.realFormat == RealFormat.ieeeDouble) 2306 { 2307 if (ex) // If exponent is non-zero 2308 { 2309 if (ex == F.EXPMASK) // infinity or NaN 2310 { 2311 if (*vl == 0x7FF0_0000_0000_0000) // positive infinity 2312 { 2313 exp = int.max; 2314 } 2315 else if (*vl == 0xFFF0_0000_0000_0000) // negative infinity 2316 exp = int.min; 2317 else 2318 { // NaN 2319 *vl |= 0x0008_0000_0000_0000; // convert NaNS to NaNQ 2320 exp = int.min; 2321 } 2322 } 2323 else 2324 { 2325 exp = (ex - F.EXPBIAS) >> 4; 2326 vu[F.EXPPOS_SHORT] = cast(ushort)((0x800F & vu[F.EXPPOS_SHORT]) | 0x3FE0); 2327 } 2328 } 2329 else if (!(*vl & 0x7FFF_FFFF_FFFF_FFFF)) 2330 { 2331 // vf is +-0.0 2332 exp = 0; 2333 } 2334 else 2335 { 2336 // subnormal 2337 vf *= F.RECIP_EPSILON; 2338 ex = vu[F.EXPPOS_SHORT] & F.EXPMASK; 2339 exp = ((ex - F.EXPBIAS) >> 4) - T.mant_dig + 1; 2340 vu[F.EXPPOS_SHORT] = 2341 cast(ushort)(((-1 - F.EXPMASK) & vu[F.EXPPOS_SHORT]) | 0x3FE0); 2342 } 2343 return vf; 2344 } 2345 else static if (F.realFormat == RealFormat.ieeeSingle) 2346 { 2347 if (ex) // If exponent is non-zero 2348 { 2349 if (ex == F.EXPMASK) // infinity or NaN 2350 { 2351 if (*vi == 0x7F80_0000) // positive infinity 2352 { 2353 exp = int.max; 2354 } 2355 else if (*vi == 0xFF80_0000) // negative infinity 2356 exp = int.min; 2357 else 2358 { // NaN 2359 *vi |= 0x0040_0000; // convert NaNS to NaNQ 2360 exp = int.min; 2361 } 2362 } 2363 else 2364 { 2365 exp = (ex - F.EXPBIAS) >> 7; 2366 vu[F.EXPPOS_SHORT] = cast(ushort)((0x807F & vu[F.EXPPOS_SHORT]) | 0x3F00); 2367 } 2368 } 2369 else if (!(*vi & 0x7FFF_FFFF)) 2370 { 2371 // vf is +-0.0 2372 exp = 0; 2373 } 2374 else 2375 { 2376 // subnormal 2377 vf *= F.RECIP_EPSILON; 2378 ex = vu[F.EXPPOS_SHORT] & F.EXPMASK; 2379 exp = ((ex - F.EXPBIAS) >> 7) - T.mant_dig + 1; 2380 vu[F.EXPPOS_SHORT] = 2381 cast(ushort)(((-1 - F.EXPMASK) & vu[F.EXPPOS_SHORT]) | 0x3F00); 2382 } 2383 return vf; 2384 } 2385 else // static if (F.realFormat == RealFormat.ibmExtended) 2386 { 2387 assert(0, "frexp not implemented"); 2388 } 2389 } 2390 2391 /// 2392 @safe unittest 2393 { 2394 import std.math.operations : isClose; 2395 2396 int exp; 2397 real mantissa = frexp(123.456L, exp); 2398 2399 assert(isClose(mantissa * pow(2.0L, cast(real) exp), 123.456L)); 2400 2401 assert(frexp(-real.nan, exp) && exp == int.min); 2402 assert(frexp(real.nan, exp) && exp == int.min); 2403 assert(frexp(-real.infinity, exp) == -real.infinity && exp == int.min); 2404 assert(frexp(real.infinity, exp) == real.infinity && exp == int.max); 2405 assert(frexp(-0.0, exp) == -0.0 && exp == 0); 2406 assert(frexp(0.0, exp) == 0.0 && exp == 0); 2407 } 2408 2409 @safe @nogc nothrow unittest 2410 { 2411 import std.math.operations : isClose; 2412 2413 int exp; 2414 real mantissa = frexp(123.456L, exp); 2415 2416 // check if values are equal to 19 decimal digits of precision 2417 assert(isClose(mantissa * pow(2.0L, cast(real) exp), 123.456L, 1e-18)); 2418 } 2419 2420 @safe unittest 2421 { 2422 import std.math : floatTraits, RealFormat; 2423 import std.math.traits : isIdentical; 2424 import std.meta : AliasSeq; 2425 import std.typecons : tuple, Tuple; 2426 2427 static foreach (T; AliasSeq!(real, double, float)) 2428 {{ 2429 Tuple!(T, T, int)[] vals = [ // x,frexp,exp 2430 tuple(T(0.0), T( 0.0 ), 0), 2431 tuple(T(-0.0), T( -0.0), 0), 2432 tuple(T(1.0), T( .5 ), 1), 2433 tuple(T(-1.0), T( -.5 ), 1), 2434 tuple(T(2.0), T( .5 ), 2), 2435 tuple(T(float.min_normal/2.0f), T(.5), -126), 2436 tuple(T.infinity, T.infinity, int.max), 2437 tuple(-T.infinity, -T.infinity, int.min), 2438 tuple(T.nan, T.nan, int.min), 2439 tuple(-T.nan, -T.nan, int.min), 2440 2441 // https://issues.dlang.org/show_bug.cgi?id=16026: 2442 tuple(3 * (T.min_normal * T.epsilon), T( .75), (T.min_exp - T.mant_dig) + 2) 2443 ]; 2444 2445 foreach (elem; vals) 2446 { 2447 T x = elem[0]; 2448 T e = elem[1]; 2449 int exp = elem[2]; 2450 int eptr; 2451 T v = frexp(x, eptr); 2452 assert(isIdentical(e, v)); 2453 assert(exp == eptr); 2454 } 2455 2456 static if (floatTraits!(T).realFormat == RealFormat.ieeeExtended) 2457 { 2458 static T[3][] extendedvals = [ // x,frexp,exp 2459 [0x1.a5f1c2eb3fe4efp+73L, 0x1.A5F1C2EB3FE4EFp-1L, 74], // normal 2460 [0x1.fa01712e8f0471ap-1064L, 0x1.fa01712e8f0471ap-1L, -1063], 2461 [T.min_normal, .5, -16381], 2462 [T.min_normal/2.0L, .5, -16382] // subnormal 2463 ]; 2464 foreach (elem; extendedvals) 2465 { 2466 T x = elem[0]; 2467 T e = elem[1]; 2468 int exp = cast(int) elem[2]; 2469 int eptr; 2470 T v = frexp(x, eptr); 2471 assert(isIdentical(e, v)); 2472 assert(exp == eptr); 2473 } 2474 } 2475 }} 2476 2477 // CTFE 2478 alias CtfeFrexpResult= Tuple!(real, int); 2479 static CtfeFrexpResult ctfeFrexp(T)(const T value) 2480 { 2481 int exp; 2482 auto significand = frexp(value, exp); 2483 return CtfeFrexpResult(significand, exp); 2484 } 2485 static foreach (T; AliasSeq!(real, double, float)) 2486 {{ 2487 enum Tuple!(T, T, int)[] vals = [ // x,frexp,exp 2488 tuple(T(0.0), T( 0.0 ), 0), 2489 tuple(T(-0.0), T( -0.0), 0), 2490 tuple(T(1.0), T( .5 ), 1), 2491 tuple(T(-1.0), T( -.5 ), 1), 2492 tuple(T(2.0), T( .5 ), 2), 2493 tuple(T(float.min_normal/2.0f), T(.5), -126), 2494 tuple(T.infinity, T.infinity, int.max), 2495 tuple(-T.infinity, -T.infinity, int.min), 2496 tuple(T.nan, T.nan, int.min), 2497 tuple(-T.nan, -T.nan, int.min), 2498 2499 // https://issues.dlang.org/show_bug.cgi?id=16026: 2500 tuple(3 * (T.min_normal * T.epsilon), T( .75), (T.min_exp - T.mant_dig) + 2) 2501 ]; 2502 2503 static foreach (elem; vals) 2504 { 2505 static assert(ctfeFrexp(elem[0]) is CtfeFrexpResult(elem[1], elem[2])); 2506 } 2507 2508 static if (floatTraits!(T).realFormat == RealFormat.ieeeExtended) 2509 { 2510 enum T[3][] extendedvals = [ // x,frexp,exp 2511 [0x1.a5f1c2eb3fe4efp+73L, 0x1.A5F1C2EB3FE4EFp-1L, 74], // normal 2512 [0x1.fa01712e8f0471ap-1064L, 0x1.fa01712e8f0471ap-1L, -1063], 2513 [T.min_normal, .5, -16381], 2514 [T.min_normal/2.0L, .5, -16382] // subnormal 2515 ]; 2516 static foreach (elem; extendedvals) 2517 { 2518 static assert(ctfeFrexp(elem[0]) is CtfeFrexpResult(elem[1], cast(int) elem[2])); 2519 } 2520 } 2521 }} 2522 } 2523 2524 @safe unittest 2525 { 2526 import std.meta : AliasSeq; 2527 void foo() { 2528 static foreach (T; AliasSeq!(real, double, float)) 2529 {{ 2530 int exp; 2531 const T a = 1; 2532 immutable T b = 2; 2533 auto c = frexp(a, exp); 2534 auto d = frexp(b, exp); 2535 }} 2536 } 2537 } 2538 2539 /****************************************** 2540 * Extracts the exponent of x as a signed integral value. 2541 * 2542 * If x is not a special value, the result is the same as 2543 * $(D cast(int) logb(x)). 2544 * 2545 * $(TABLE_SV 2546 * $(TR $(TH x) $(TH ilogb(x)) $(TH Range error?)) 2547 * $(TR $(TD 0) $(TD FP_ILOGB0) $(TD yes)) 2548 * $(TR $(TD $(PLUSMN)$(INFIN)) $(TD int.max) $(TD no)) 2549 * $(TR $(TD $(NAN)) $(TD FP_ILOGBNAN) $(TD no)) 2550 * ) 2551 */ 2552 int ilogb(T)(const T x) @trusted pure nothrow @nogc 2553 if (isFloatingPoint!T) 2554 { 2555 import std.math : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB; 2556 2557 import core.bitop : bsr; 2558 alias F = floatTraits!T; 2559 2560 union floatBits 2561 { 2562 T rv; 2563 ushort[T.sizeof/2] vu; 2564 uint[T.sizeof/4] vui; 2565 static if (T.sizeof >= 8) 2566 ulong[T.sizeof/8] vul; 2567 } 2568 floatBits y = void; 2569 y.rv = x; 2570 2571 int ex = y.vu[F.EXPPOS_SHORT] & F.EXPMASK; 2572 static if (F.realFormat == RealFormat.ieeeExtended || 2573 F.realFormat == RealFormat.ieeeExtended53) 2574 { 2575 if (ex) 2576 { 2577 // If exponent is non-zero 2578 if (ex == F.EXPMASK) // infinity or NaN 2579 { 2580 if (y.vul[0] & 0x7FFF_FFFF_FFFF_FFFF) // NaN 2581 return FP_ILOGBNAN; 2582 else // +-infinity 2583 return int.max; 2584 } 2585 else 2586 { 2587 return ex - F.EXPBIAS - 1; 2588 } 2589 } 2590 else if (!y.vul[0]) 2591 { 2592 // vf is +-0.0 2593 return FP_ILOGB0; 2594 } 2595 else 2596 { 2597 // subnormal 2598 return ex - F.EXPBIAS - T.mant_dig + 1 + bsr(y.vul[0]); 2599 } 2600 } 2601 else static if (F.realFormat == RealFormat.ieeeQuadruple) 2602 { 2603 if (ex) // If exponent is non-zero 2604 { 2605 if (ex == F.EXPMASK) 2606 { 2607 // infinity or NaN 2608 if (y.vul[MANTISSA_LSB] | ( y.vul[MANTISSA_MSB] & 0x0000_FFFF_FFFF_FFFF)) // NaN 2609 return FP_ILOGBNAN; 2610 else // +- infinity 2611 return int.max; 2612 } 2613 else 2614 { 2615 return ex - F.EXPBIAS - 1; 2616 } 2617 } 2618 else if ((y.vul[MANTISSA_LSB] | (y.vul[MANTISSA_MSB] & 0x0000_FFFF_FFFF_FFFF)) == 0) 2619 { 2620 // vf is +-0.0 2621 return FP_ILOGB0; 2622 } 2623 else 2624 { 2625 // subnormal 2626 const ulong msb = y.vul[MANTISSA_MSB] & 0x0000_FFFF_FFFF_FFFF; 2627 const ulong lsb = y.vul[MANTISSA_LSB]; 2628 if (msb) 2629 return ex - F.EXPBIAS - T.mant_dig + 1 + bsr(msb) + 64; 2630 else 2631 return ex - F.EXPBIAS - T.mant_dig + 1 + bsr(lsb); 2632 } 2633 } 2634 else static if (F.realFormat == RealFormat.ieeeDouble) 2635 { 2636 if (ex) // If exponent is non-zero 2637 { 2638 if (ex == F.EXPMASK) // infinity or NaN 2639 { 2640 if ((y.vul[0] & 0x7FFF_FFFF_FFFF_FFFF) == 0x7FF0_0000_0000_0000) // +- infinity 2641 return int.max; 2642 else // NaN 2643 return FP_ILOGBNAN; 2644 } 2645 else 2646 { 2647 return ((ex - F.EXPBIAS) >> 4) - 1; 2648 } 2649 } 2650 else if (!(y.vul[0] & 0x7FFF_FFFF_FFFF_FFFF)) 2651 { 2652 // vf is +-0.0 2653 return FP_ILOGB0; 2654 } 2655 else 2656 { 2657 // subnormal 2658 enum MANTISSAMASK_64 = ((cast(ulong) F.MANTISSAMASK_INT) << 32) | 0xFFFF_FFFF; 2659 return ((ex - F.EXPBIAS) >> 4) - T.mant_dig + 1 + bsr(y.vul[0] & MANTISSAMASK_64); 2660 } 2661 } 2662 else static if (F.realFormat == RealFormat.ieeeSingle) 2663 { 2664 if (ex) // If exponent is non-zero 2665 { 2666 if (ex == F.EXPMASK) // infinity or NaN 2667 { 2668 if ((y.vui[0] & 0x7FFF_FFFF) == 0x7F80_0000) // +- infinity 2669 return int.max; 2670 else // NaN 2671 return FP_ILOGBNAN; 2672 } 2673 else 2674 { 2675 return ((ex - F.EXPBIAS) >> 7) - 1; 2676 } 2677 } 2678 else if (!(y.vui[0] & 0x7FFF_FFFF)) 2679 { 2680 // vf is +-0.0 2681 return FP_ILOGB0; 2682 } 2683 else 2684 { 2685 // subnormal 2686 const uint mantissa = y.vui[0] & F.MANTISSAMASK_INT; 2687 return ((ex - F.EXPBIAS) >> 7) - T.mant_dig + 1 + bsr(mantissa); 2688 } 2689 } 2690 else // static if (F.realFormat == RealFormat.ibmExtended) 2691 { 2692 assert(0, "ilogb not implemented"); 2693 } 2694 } 2695 /// ditto 2696 int ilogb(T)(const T x) @safe pure nothrow @nogc 2697 if (isIntegral!T && isUnsigned!T) 2698 { 2699 import core.bitop : bsr; 2700 if (x == 0) 2701 return FP_ILOGB0; 2702 else 2703 { 2704 static assert(T.sizeof <= ulong.sizeof, "integer size too large for the current ilogb implementation"); 2705 return bsr(x); 2706 } 2707 } 2708 /// ditto 2709 int ilogb(T)(const T x) @safe pure nothrow @nogc 2710 if (isIntegral!T && isSigned!T) 2711 { 2712 import std.traits : Unsigned; 2713 // Note: abs(x) can not be used because the return type is not Unsigned and 2714 // the return value would be wrong for x == int.min 2715 Unsigned!T absx = x >= 0 ? x : -x; 2716 return ilogb(absx); 2717 } 2718 2719 /// 2720 @safe pure unittest 2721 { 2722 assert(ilogb(1) == 0); 2723 assert(ilogb(3) == 1); 2724 assert(ilogb(3.0) == 1); 2725 assert(ilogb(100_000_000) == 26); 2726 2727 assert(ilogb(0) == FP_ILOGB0); 2728 assert(ilogb(0.0) == FP_ILOGB0); 2729 assert(ilogb(double.nan) == FP_ILOGBNAN); 2730 assert(ilogb(double.infinity) == int.max); 2731 } 2732 2733 /** 2734 Special return values of $(LREF ilogb). 2735 */ 2736 alias FP_ILOGB0 = core.stdc.math.FP_ILOGB0; 2737 /// ditto 2738 alias FP_ILOGBNAN = core.stdc.math.FP_ILOGBNAN; 2739 2740 /// 2741 @safe pure unittest 2742 { 2743 assert(ilogb(0) == FP_ILOGB0); 2744 assert(ilogb(0.0) == FP_ILOGB0); 2745 assert(ilogb(double.nan) == FP_ILOGBNAN); 2746 } 2747 2748 @safe nothrow @nogc unittest 2749 { 2750 import std.math : floatTraits, RealFormat; 2751 import std.math.operations : nextUp; 2752 import std.meta : AliasSeq; 2753 import std.typecons : Tuple; 2754 static foreach (F; AliasSeq!(float, double, real)) 2755 {{ 2756 alias T = Tuple!(F, int); 2757 T[13] vals = // x, ilogb(x) 2758 [ 2759 T( F.nan , FP_ILOGBNAN ), 2760 T( -F.nan , FP_ILOGBNAN ), 2761 T( F.infinity, int.max ), 2762 T( -F.infinity, int.max ), 2763 T( 0.0 , FP_ILOGB0 ), 2764 T( -0.0 , FP_ILOGB0 ), 2765 T( 2.0 , 1 ), 2766 T( 2.0001 , 1 ), 2767 T( 1.9999 , 0 ), 2768 T( 0.5 , -1 ), 2769 T( 123.123 , 6 ), 2770 T( -123.123 , 6 ), 2771 T( 0.123 , -4 ), 2772 ]; 2773 2774 foreach (elem; vals) 2775 { 2776 assert(ilogb(elem[0]) == elem[1]); 2777 } 2778 }} 2779 2780 // min_normal and subnormals 2781 assert(ilogb(-float.min_normal) == -126); 2782 assert(ilogb(nextUp(-float.min_normal)) == -127); 2783 assert(ilogb(nextUp(-float(0.0))) == -149); 2784 assert(ilogb(-double.min_normal) == -1022); 2785 assert(ilogb(nextUp(-double.min_normal)) == -1023); 2786 assert(ilogb(nextUp(-double(0.0))) == -1074); 2787 static if (floatTraits!(real).realFormat == RealFormat.ieeeExtended) 2788 { 2789 assert(ilogb(-real.min_normal) == -16382); 2790 assert(ilogb(nextUp(-real.min_normal)) == -16383); 2791 assert(ilogb(nextUp(-real(0.0))) == -16445); 2792 } 2793 else static if (floatTraits!(real).realFormat == RealFormat.ieeeDouble) 2794 { 2795 assert(ilogb(-real.min_normal) == -1022); 2796 assert(ilogb(nextUp(-real.min_normal)) == -1023); 2797 assert(ilogb(nextUp(-real(0.0))) == -1074); 2798 } 2799 2800 // test integer types 2801 assert(ilogb(0) == FP_ILOGB0); 2802 assert(ilogb(int.max) == 30); 2803 assert(ilogb(int.min) == 31); 2804 assert(ilogb(uint.max) == 31); 2805 assert(ilogb(long.max) == 62); 2806 assert(ilogb(long.min) == 63); 2807 assert(ilogb(ulong.max) == 63); 2808 } 2809 2810 /******************************************* 2811 * Compute n * 2$(SUPERSCRIPT exp) 2812 * References: frexp 2813 */ 2814 2815 pragma(inline, true) 2816 real ldexp(real n, int exp) @safe pure nothrow @nogc { return core.math.ldexp(n, exp); } 2817 ///ditto 2818 pragma(inline, true) 2819 double ldexp(double n, int exp) @safe pure nothrow @nogc { return core.math.ldexp(n, exp); } 2820 ///ditto 2821 pragma(inline, true) 2822 float ldexp(float n, int exp) @safe pure nothrow @nogc { return core.math.ldexp(n, exp); } 2823 2824 /// 2825 @nogc @safe pure nothrow unittest 2826 { 2827 import std.meta : AliasSeq; 2828 static foreach (T; AliasSeq!(float, double, real)) 2829 {{ 2830 T r; 2831 2832 r = ldexp(3.0L, 3); 2833 assert(r == 24); 2834 2835 r = ldexp(cast(T) 3.0, cast(int) 3); 2836 assert(r == 24); 2837 2838 T n = 3.0; 2839 int exp = 3; 2840 r = ldexp(n, exp); 2841 assert(r == 24); 2842 }} 2843 } 2844 2845 @safe pure nothrow @nogc unittest 2846 { 2847 import std.math : floatTraits, RealFormat; 2848 2849 static if (floatTraits!(real).realFormat == RealFormat.ieeeExtended || 2850 floatTraits!(real).realFormat == RealFormat.ieeeExtended53 || 2851 floatTraits!(real).realFormat == RealFormat.ieeeQuadruple) 2852 { 2853 assert(ldexp(1.0L, -16384) == 0x1p-16384L); 2854 assert(ldexp(1.0L, -16382) == 0x1p-16382L); 2855 int x; 2856 real n = frexp(0x1p-16384L, x); 2857 assert(n == 0.5L); 2858 assert(x==-16383); 2859 assert(ldexp(n, x)==0x1p-16384L); 2860 } 2861 else static if (floatTraits!(real).realFormat == RealFormat.ieeeDouble) 2862 { 2863 assert(ldexp(1.0L, -1024) == 0x1p-1024L); 2864 assert(ldexp(1.0L, -1022) == 0x1p-1022L); 2865 int x; 2866 real n = frexp(0x1p-1024L, x); 2867 assert(n == 0.5L); 2868 assert(x==-1023); 2869 assert(ldexp(n, x)==0x1p-1024L); 2870 } 2871 else static assert(false, "Floating point type real not supported"); 2872 } 2873 2874 /* workaround https://issues.dlang.org/show_bug.cgi?id=14718 2875 float parsing depends on platform strtold 2876 @safe pure nothrow @nogc unittest 2877 { 2878 assert(ldexp(1.0, -1024) == 0x1p-1024); 2879 assert(ldexp(1.0, -1022) == 0x1p-1022); 2880 int x; 2881 double n = frexp(0x1p-1024, x); 2882 assert(n == 0.5); 2883 assert(x==-1023); 2884 assert(ldexp(n, x)==0x1p-1024); 2885 } 2886 2887 @safe pure nothrow @nogc unittest 2888 { 2889 assert(ldexp(1.0f, -128) == 0x1p-128f); 2890 assert(ldexp(1.0f, -126) == 0x1p-126f); 2891 int x; 2892 float n = frexp(0x1p-128f, x); 2893 assert(n == 0.5f); 2894 assert(x==-127); 2895 assert(ldexp(n, x)==0x1p-128f); 2896 } 2897 */ 2898 2899 @safe @nogc nothrow unittest 2900 { 2901 import std.math.operations : isClose; 2902 2903 static real[3][] vals = // value,exp,ldexp 2904 [ 2905 [ 0, 0, 0], 2906 [ 1, 0, 1], 2907 [ -1, 0, -1], 2908 [ 1, 1, 2], 2909 [ 123, 10, 125952], 2910 [ real.max, int.max, real.infinity], 2911 [ real.max, -int.max, 0], 2912 [ real.min_normal, -int.max, 0], 2913 ]; 2914 int i; 2915 2916 for (i = 0; i < vals.length; i++) 2917 { 2918 real x = vals[i][0]; 2919 int exp = cast(int) vals[i][1]; 2920 real z = vals[i][2]; 2921 real l = ldexp(x, exp); 2922 2923 assert(isClose(z, l, 1e-6)); 2924 } 2925 2926 real function(real, int) pldexp = &ldexp; 2927 assert(pldexp != null); 2928 } 2929 2930 private 2931 { 2932 // Coefficients shared across log(), log2(), log10(), log1p(). 2933 template LogCoeffs(T) 2934 { 2935 import std.math : floatTraits, RealFormat; 2936 2937 static if (floatTraits!T.realFormat == RealFormat.ieeeQuadruple) 2938 { 2939 // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x)/Q(x) 2940 // Theoretical peak relative error = 5.3e-37 2941 static immutable real[13] logP = [ 2942 1.313572404063446165910279910527789794488E4L, 2943 7.771154681358524243729929227226708890930E4L, 2944 2.014652742082537582487669938141683759923E5L, 2945 3.007007295140399532324943111654767187848E5L, 2946 2.854829159639697837788887080758954924001E5L, 2947 1.797628303815655343403735250238293741397E5L, 2948 7.594356839258970405033155585486712125861E4L, 2949 2.128857716871515081352991964243375186031E4L, 2950 3.824952356185897735160588078446136783779E3L, 2951 4.114517881637811823002128927449878962058E2L, 2952 2.321125933898420063925789532045674660756E1L, 2953 4.998469661968096229986658302195402690910E-1L, 2954 1.538612243596254322971797716843006400388E-6L 2955 ]; 2956 static immutable real[13] logQ = [ 2957 3.940717212190338497730839731583397586124E4L, 2958 2.626900195321832660448791748036714883242E5L, 2959 7.777690340007566932935753241556479363645E5L, 2960 1.347518538384329112529391120390701166528E6L, 2961 1.514882452993549494932585972882995548426E6L, 2962 1.158019977462989115839826904108208787040E6L, 2963 6.132189329546557743179177159925690841200E5L, 2964 2.248234257620569139969141618556349415120E5L, 2965 5.605842085972455027590989944010492125825E4L, 2966 9.147150349299596453976674231612674085381E3L, 2967 9.104928120962988414618126155557301584078E2L, 2968 4.839208193348159620282142911143429644326E1L, 2969 1.0 2970 ]; 2971 2972 // log2 uses the same coefficients as log. 2973 alias log2P = logP; 2974 alias log2Q = logQ; 2975 2976 // log10 uses the same coefficients as log. 2977 alias log10P = logP; 2978 alias log10Q = logQ; 2979 2980 // Coefficients for log(x) = z + z^^3 R(z^^2)/S(z^^2) 2981 // where z = 2(x-1)/(x+1) 2982 // Theoretical peak relative error = 1.1e-35 2983 static immutable real[6] logR = [ 2984 1.418134209872192732479751274970992665513E5L, 2985 -8.977257995689735303686582344659576526998E4L, 2986 2.048819892795278657810231591630928516206E4L, 2987 -2.024301798136027039250415126250455056397E3L, 2988 8.057002716646055371965756206836056074715E1L, 2989 -8.828896441624934385266096344596648080902E-1L 2990 ]; 2991 static immutable real[7] logS = [ 2992 1.701761051846631278975701529965589676574E6L, 2993 -1.332535117259762928288745111081235577029E6L, 2994 4.001557694070773974936904547424676279307E5L, 2995 -5.748542087379434595104154610899551484314E4L, 2996 3.998526750980007367835804959888064681098E3L, 2997 -1.186359407982897997337150403816839480438E2L, 2998 1.0 2999 ]; 3000 } 3001 else static if (floatTraits!T.realFormat == RealFormat.ieeeExtended || 3002 floatTraits!T.realFormat == RealFormat.ieeeExtended53) 3003 { 3004 // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x)/Q(x) 3005 // Theoretical peak relative error = 2.32e-20 3006 static immutable real[7] logP = [ 3007 2.0039553499201281259648E1L, 3008 5.7112963590585538103336E1L, 3009 6.0949667980987787057556E1L, 3010 2.9911919328553073277375E1L, 3011 6.5787325942061044846969E0L, 3012 4.9854102823193375972212E-1L, 3013 4.5270000862445199635215E-5L, 3014 ]; 3015 static immutable real[7] logQ = [ 3016 6.0118660497603843919306E1L, 3017 2.1642788614495947685003E2L, 3018 3.0909872225312059774938E2L, 3019 2.2176239823732856465394E2L, 3020 8.3047565967967209469434E1L, 3021 1.5062909083469192043167E1L, 3022 1.0000000000000000000000E0L, 3023 ]; 3024 3025 // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x)/Q(x) 3026 // Theoretical peak relative error = 6.2e-22 3027 static immutable real[7] log2P = [ 3028 1.0747524399916215149070E2L, 3029 3.4258224542413922935104E2L, 3030 4.2401812743503691187826E2L, 3031 2.5620629828144409632571E2L, 3032 7.7671073698359539859595E1L, 3033 1.0767376367209449010438E1L, 3034 4.9962495940332550844739E-1L, 3035 ]; 3036 static immutable real[8] log2Q = [ 3037 3.2242573199748645407652E2L, 3038 1.2695660352705325274404E3L, 3039 2.0307734695595183428202E3L, 3040 1.6911722418503949084863E3L, 3041 7.7952888181207260646090E2L, 3042 1.9444210022760132894510E2L, 3043 2.3479774160285863271658E1L, 3044 1.0000000000000000000000E0, 3045 ]; 3046 3047 // log10 uses the same coefficients as log2. 3048 alias log10P = log2P; 3049 alias log10Q = log2Q; 3050 3051 // Coefficients for log(x) = z + z^^3 R(z^^2)/S(z^^2) 3052 // where z = 2(x-1)/(x+1) 3053 // Theoretical peak relative error = 6.16e-22 3054 static immutable real[4] logR = [ 3055 -3.5717684488096787370998E1L, 3056 1.0777257190312272158094E1L, 3057 -7.1990767473014147232598E-1L, 3058 1.9757429581415468984296E-3L, 3059 ]; 3060 static immutable real[4] logS = [ 3061 -4.2861221385716144629696E2L, 3062 1.9361891836232102174846E2L, 3063 -2.6201045551331104417768E1L, 3064 1.0000000000000000000000E0L, 3065 ]; 3066 } 3067 else static if (floatTraits!T.realFormat == RealFormat.ieeeDouble) 3068 { 3069 // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x)/Q(x) 3070 static immutable double[6] logP = [ 3071 7.70838733755885391666E0, 3072 1.79368678507819816313E1, 3073 1.44989225341610930846E1, 3074 4.70579119878881725854E0, 3075 4.97494994976747001425E-1, 3076 1.01875663804580931796E-4, 3077 ]; 3078 static immutable double[6] logQ = [ 3079 2.31251620126765340583E1, 3080 7.11544750618563894466E1, 3081 8.29875266912776603211E1, 3082 4.52279145837532221105E1, 3083 1.12873587189167450590E1, 3084 1.00000000000000000000E0, 3085 ]; 3086 3087 // log2 uses the same coefficients as log. 3088 alias log2P = logP; 3089 alias log2Q = logQ; 3090 3091 // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x)/Q(x) 3092 static immutable double[7] logp1P = [ 3093 2.0039553499201281259648E1, 3094 5.7112963590585538103336E1, 3095 6.0949667980987787057556E1, 3096 2.9911919328553073277375E1, 3097 6.5787325942061044846969E0, 3098 4.9854102823193375972212E-1, 3099 4.5270000862445199635215E-5, 3100 ]; 3101 static immutable double[7] logp1Q = [ 3102 6.0118660497603843919306E1, 3103 2.1642788614495947685003E2, 3104 3.0909872225312059774938E2, 3105 2.2176239823732856465394E2, 3106 8.3047565967967209469434E1, 3107 1.5062909083469192043167E1, 3108 1.0000000000000000000000E0, 3109 ]; 3110 3111 static immutable double[7] log10P = [ 3112 1.98892446572874072159E1, 3113 5.67349287391754285487E1, 3114 6.06127134467767258030E1, 3115 2.97877425097986925891E1, 3116 6.56312093769992875930E0, 3117 4.98531067254050724270E-1, 3118 4.58482948458143443514E-5, 3119 ]; 3120 static immutable double[7] log10Q = [ 3121 5.96677339718622216300E1, 3122 2.14955586696422947765E2, 3123 3.07254189979530058263E2, 3124 2.20664384982121929218E2, 3125 8.27410449222435217021E1, 3126 1.50314182634250003249E1, 3127 1.00000000000000000000E0, 3128 ]; 3129 3130 // Coefficients for log(x) = z + z^^3 R(z)/S(z) 3131 // where z = 2(x-1)/(x+1) 3132 static immutable double[3] logR = [ 3133 -6.41409952958715622951E1, 3134 1.63866645699558079767E1, 3135 -7.89580278884799154124E-1, 3136 ]; 3137 static immutable double[4] logS = [ 3138 -7.69691943550460008604E2, 3139 3.12093766372244180303E2, 3140 -3.56722798256324312549E1, 3141 1.00000000000000000000E0, 3142 ]; 3143 } 3144 else static if (floatTraits!T.realFormat == RealFormat.ieeeSingle) 3145 { 3146 // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x) 3147 static immutable float[9] logP = [ 3148 3.3333331174E-1, 3149 -2.4999993993E-1, 3150 2.0000714765E-1, 3151 -1.6668057665E-1, 3152 1.4249322787E-1, 3153 -1.2420140846E-1, 3154 1.1676998740E-1, 3155 -1.1514610310E-1, 3156 7.0376836292E-2, 3157 ]; 3158 3159 // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x)/Q(x) 3160 static immutable float[7] logp1P = [ 3161 2.0039553499E1, 3162 5.7112963590E1, 3163 6.0949667980E1, 3164 2.9911919328E1, 3165 6.5787325942E0, 3166 4.9854102823E-1, 3167 4.5270000862E-5, 3168 ]; 3169 static immutable float[7] logp1Q = [ 3170 6.01186604976E1, 3171 2.16427886144E2, 3172 3.09098722253E2, 3173 2.21762398237E2, 3174 8.30475659679E1, 3175 1.50629090834E1, 3176 1.00000000000E0, 3177 ]; 3178 3179 // log2 and log10 uses the same coefficients as log. 3180 alias log2P = logP; 3181 alias log10P = logP; 3182 } 3183 else 3184 static assert(0, "no coefficients for log()"); 3185 } 3186 } 3187 3188 /************************************** 3189 * Calculate the natural logarithm of x. 3190 * 3191 * $(TABLE_SV 3192 * $(TR $(TH x) $(TH log(x)) $(TH divide by 0?) $(TH invalid?)) 3193 * $(TR $(TD $(PLUSMN)0.0) $(TD -$(INFIN)) $(TD yes) $(TD no)) 3194 * $(TR $(TD $(LT)0.0) $(TD $(NAN)) $(TD no) $(TD yes)) 3195 * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) $(TD no) $(TD no)) 3196 * ) 3197 */ 3198 pragma(inline, true) 3199 real log(real x) @safe pure nothrow @nogc 3200 { 3201 version (INLINE_YL2X) 3202 { 3203 import std.math.constants : LN2; 3204 return core.math.yl2x(x, LN2); 3205 } 3206 else 3207 return logImpl(x); 3208 } 3209 3210 /// ditto 3211 pragma(inline, true) 3212 double log(double x) @safe pure nothrow @nogc { return __ctfe ? cast(double) log(cast(real) x) : logImpl(x); } 3213 3214 /// ditto 3215 pragma(inline, true) 3216 float log(float x) @safe pure nothrow @nogc { return __ctfe ? cast(float) log(cast(real) x) : logImpl(x); } 3217 3218 // @@@DEPRECATED_[2.112.0]@@@ 3219 deprecated("`std.math.exponential.log` called with argument types `(int)` matches both " 3220 ~ "`log(real)`, `log(double)`, and `log(float)`. Cast argument to floating point type instead.") 3221 real log(int x) @safe pure nothrow @nogc { return log(cast(real) x); } 3222 // @@@DEPRECATED_[2.112.0]@@@ 3223 deprecated("`std.math.exponential.log` called with argument types `(uint)` matches both " 3224 ~ "`log(real)`, `log(double)`, and `log(float)`. Cast argument to floating point type instead.") 3225 real log(uint x) @safe pure nothrow @nogc { return log(cast(real) x); } 3226 // @@@DEPRECATED_[2.112.0]@@@ 3227 deprecated("`std.math.exponential.log` called with argument types `(long)` matches both " 3228 ~ "`log(real)`, `log(double)`, and `log(float)`. Cast argument to floating point type instead.") 3229 real log(long x) @safe pure nothrow @nogc { return log(cast(real) x); } 3230 // @@@DEPRECATED_[2.112.0]@@@ 3231 deprecated("`std.math.exponential.log` called with argument types `(ulong)` matches both " 3232 ~ "`log(real)`, `log(double)`, and `log(float)`. Cast argument to floating point type instead.") 3233 real log(ulong x) @safe pure nothrow @nogc { return log(cast(real) x); } 3234 3235 /// 3236 @safe pure nothrow @nogc unittest 3237 { 3238 import std.math.operations : feqrel; 3239 import std.math.constants : E; 3240 3241 assert(feqrel(log(E), 1) >= real.mant_dig - 1); 3242 } 3243 3244 private T logImpl(T, bool LOG1P = false)(T x) @safe pure nothrow @nogc 3245 { 3246 import std.math.constants : SQRT1_2; 3247 import std.math.algebraic : poly; 3248 import std.math.traits : isInfinity, isNaN, signbit; 3249 import std.math : floatTraits, RealFormat; 3250 3251 alias coeffs = LogCoeffs!T; 3252 alias F = floatTraits!T; 3253 3254 static if (LOG1P) 3255 { 3256 const T xm1 = x; 3257 x = x + 1.0; 3258 } 3259 3260 static if (F.realFormat == RealFormat.ieeeExtended || 3261 F.realFormat == RealFormat.ieeeExtended53 || 3262 F.realFormat == RealFormat.ieeeQuadruple) 3263 { 3264 // C1 + C2 = LN2. 3265 enum T C1 = 6.93145751953125E-1L; 3266 enum T C2 = 1.428606820309417232121458176568075500134E-6L; 3267 } 3268 else static if (F.realFormat == RealFormat.ieeeDouble) 3269 { 3270 enum T C1 = 0.693359375; 3271 enum T C2 = -2.121944400546905827679e-4; 3272 } 3273 else static if (F.realFormat == RealFormat.ieeeSingle) 3274 { 3275 enum T C1 = 0.693359375; 3276 enum T C2 = -2.12194440e-4; 3277 } 3278 else 3279 static assert(0, "Not implemented for this architecture"); 3280 3281 // Special cases. 3282 if (isNaN(x)) 3283 return x; 3284 if (isInfinity(x) && !signbit(x)) 3285 return x; 3286 if (x == 0.0) 3287 return -T.infinity; 3288 if (x < 0.0) 3289 return T.nan; 3290 3291 // Separate mantissa from exponent. 3292 // Note, frexp is used so that denormal numbers will be handled properly. 3293 T y, z; 3294 int exp; 3295 3296 x = frexp(x, exp); 3297 3298 static if (F.realFormat == RealFormat.ieeeDouble || 3299 F.realFormat == RealFormat.ieeeExtended || 3300 F.realFormat == RealFormat.ieeeExtended53 || 3301 F.realFormat == RealFormat.ieeeQuadruple) 3302 { 3303 // Logarithm using log(x) = z + z^^3 R(z) / S(z), 3304 // where z = 2(x - 1)/(x + 1) 3305 if ((exp > 2) || (exp < -2)) 3306 { 3307 if (x < SQRT1_2) 3308 { // 2(2x - 1)/(2x + 1) 3309 exp -= 1; 3310 z = x - 0.5; 3311 y = 0.5 * z + 0.5; 3312 } 3313 else 3314 { // 2(x - 1)/(x + 1) 3315 z = x - 0.5; 3316 z -= 0.5; 3317 y = 0.5 * x + 0.5; 3318 } 3319 x = z / y; 3320 z = x * x; 3321 z = x * (z * poly(z, coeffs.logR) / poly(z, coeffs.logS)); 3322 z += exp * C2; 3323 z += x; 3324 z += exp * C1; 3325 3326 return z; 3327 } 3328 } 3329 3330 // Logarithm using log(1 + x) = x - .5x^^2 + x^^3 P(x) / Q(x) 3331 if (x < SQRT1_2) 3332 { 3333 exp -= 1; 3334 static if (LOG1P) 3335 { 3336 if (exp != 0) 3337 x = 2.0 * x - 1.0; 3338 else 3339 x = xm1; 3340 } 3341 else 3342 x = 2.0 * x - 1.0; 3343 3344 } 3345 else 3346 { 3347 static if (LOG1P) 3348 { 3349 if (exp != 0) 3350 x = x - 1.0; 3351 else 3352 x = xm1; 3353 } 3354 else 3355 x = x - 1.0; 3356 } 3357 z = x * x; 3358 static if (F.realFormat == RealFormat.ieeeSingle) 3359 y = x * (z * poly(x, coeffs.logP)); 3360 else 3361 y = x * (z * poly(x, coeffs.logP) / poly(x, coeffs.logQ)); 3362 y += exp * C2; 3363 z = y - 0.5 * z; 3364 3365 // Note, the sum of above terms does not exceed x/4, 3366 // so it contributes at most about 1/4 lsb to the error. 3367 z += x; 3368 z += exp * C1; 3369 3370 return z; 3371 } 3372 3373 @safe @nogc nothrow unittest 3374 { 3375 import std.math : floatTraits, RealFormat; 3376 import std.meta : AliasSeq; 3377 3378 static void testLog(T)(T[2][] vals) 3379 { 3380 import std.math.operations : isClose; 3381 import std.math.traits : isNaN; 3382 foreach (ref pair; vals) 3383 { 3384 if (isNaN(pair[1])) 3385 assert(isNaN(log(pair[0]))); 3386 else 3387 assert(isClose(log(pair[0]), pair[1])); 3388 } 3389 } 3390 static foreach (F; AliasSeq!(float, double, real)) 3391 {{ 3392 scope F[2][] vals = [ 3393 [F(1), F(0x0p+0)], [F(2), F(0x1.62e42fefa39ef358p-1)], 3394 [F(4), F(0x1.62e42fefa39ef358p+0)], [F(8), F(0x1.0a2b23f3bab73682p+1)], 3395 [F(16), F(0x1.62e42fefa39ef358p+1)], [F(32), F(0x1.bb9d3beb8c86b02ep+1)], 3396 [F(64), F(0x1.0a2b23f3bab73682p+2)], [F(128), F(0x1.3687a9f1af2b14ecp+2)], 3397 [F(256), F(0x1.62e42fefa39ef358p+2)], [F(512), F(0x1.8f40b5ed9812d1c2p+2)], 3398 [F(1024), F(0x1.bb9d3beb8c86b02ep+2)], [F(2048), F(0x1.e7f9c1e980fa8e98p+2)], 3399 [F(3), F(0x1.193ea7aad030a976p+0)], [F(5), F(0x1.9c041f7ed8d336bp+0)], 3400 [F(7), F(0x1.f2272ae325a57546p+0)], [F(15), F(0x1.5aa16394d481f014p+1)], 3401 [F(17), F(0x1.6aa6bc1fa7f79cfp+1)], [F(31), F(0x1.b78ce48912b59f12p+1)], 3402 [F(33), F(0x1.bf8d8f4d5b8d1038p+1)], [F(63), F(0x1.09291e8e3181b20ep+2)], 3403 [F(65), F(0x1.0b292939429755ap+2)], [F(-0), -F.infinity], [F(0), -F.infinity], 3404 [F(0.1), F(-0x1.26bb1bbb5551582ep+1)], [F(0.25), F(-0x1.62e42fefa39ef358p+0)], 3405 [F(0.75), F(-0x1.269621134db92784p-2)], [F(0.875), F(-0x1.1178e8227e47bde4p-3)], 3406 [F(10), F(0x1.26bb1bbb5551582ep+1)], [F(100), F(0x1.26bb1bbb5551582ep+2)], 3407 [F(10000), F(0x1.26bb1bbb5551582ep+3)], 3408 ]; 3409 testLog(vals); 3410 }} 3411 { 3412 float[2][16] vals = [ 3413 [float.nan, float.nan],[-float.nan, float.nan], 3414 [float.infinity, float.infinity], [-float.infinity, float.nan], 3415 [float.min_normal, -0x1.5d58ap+6f], [-float.min_normal, float.nan], 3416 [float.max, 0x1.62e43p+6f], [-float.max, float.nan], 3417 [float.min_normal / 2, -0x1.601e68p+6f], [-float.min_normal / 2, float.nan], 3418 [float.max / 2, 0x1.601e68p+6f], [-float.max / 2, float.nan], 3419 [float.min_normal / 3, -0x1.61bd9ap+6f], [-float.min_normal / 3, float.nan], 3420 [float.max / 3, 0x1.5e7f36p+6f], [-float.max / 3, float.nan], 3421 ]; 3422 testLog(vals); 3423 } 3424 { 3425 double[2][16] vals = [ 3426 [double.nan, double.nan],[-double.nan, double.nan], 3427 [double.infinity, double.infinity], [-double.infinity, double.nan], 3428 [double.min_normal, -0x1.6232bdd7abcd2p+9], [-double.min_normal, double.nan], 3429 [double.max, 0x1.62e42fefa39efp+9], [-double.max, double.nan], 3430 [double.min_normal / 2, -0x1.628b76e3a7b61p+9], [-double.min_normal / 2, double.nan], 3431 [double.max / 2, 0x1.628b76e3a7b61p+9], [-double.max / 2, double.nan], 3432 [double.min_normal / 3, -0x1.62bf5d2b81354p+9], [-double.min_normal / 3, double.nan], 3433 [double.max / 3, 0x1.6257909bce36ep+9], [-double.max / 3, double.nan], 3434 ]; 3435 testLog(vals); 3436 } 3437 alias F = floatTraits!real; 3438 static if (F.realFormat == RealFormat.ieeeExtended || F.realFormat == RealFormat.ieeeQuadruple) 3439 {{ 3440 real[2][16] vals = [ 3441 [real.nan, real.nan],[-real.nan, real.nan], 3442 [real.infinity, real.infinity], [-real.infinity, real.nan], 3443 [real.min_normal, -0x1.62d918ce2421d66p+13L], [-real.min_normal, real.nan], 3444 [real.max, 0x1.62e42fefa39ef358p+13L], [-real.max, real.nan], 3445 [real.min_normal / 2, -0x1.62dea45ee3e064dcp+13L], [-real.min_normal / 2, real.nan], 3446 [real.max / 2, 0x1.62dea45ee3e064dcp+13L], [-real.max / 2, real.nan], 3447 [real.min_normal / 3, -0x1.62e1e2c3617857e6p+13L], [-real.min_normal / 3, real.nan], 3448 [real.max / 3, 0x1.62db65fa664871d2p+13L], [-real.max / 3, real.nan], 3449 ]; 3450 testLog(vals); 3451 }} 3452 } 3453 3454 /************************************** 3455 * Calculate the base-10 logarithm of x. 3456 * 3457 * $(TABLE_SV 3458 * $(TR $(TH x) $(TH log10(x)) $(TH divide by 0?) $(TH invalid?)) 3459 * $(TR $(TD $(PLUSMN)0.0) $(TD -$(INFIN)) $(TD yes) $(TD no)) 3460 * $(TR $(TD $(LT)0.0) $(TD $(NAN)) $(TD no) $(TD yes)) 3461 * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) $(TD no) $(TD no)) 3462 * ) 3463 */ 3464 pragma(inline, true) 3465 real log10(real x) @safe pure nothrow @nogc 3466 { 3467 version (INLINE_YL2X) 3468 { 3469 import std.math.constants : LOG2; 3470 return core.math.yl2x(x, LOG2); 3471 } 3472 else 3473 return log10Impl(x); 3474 } 3475 3476 /// ditto 3477 pragma(inline, true) 3478 double log10(double x) @safe pure nothrow @nogc { return __ctfe ? cast(double) log10(cast(real) x) : log10Impl(x); } 3479 3480 /// ditto 3481 pragma(inline, true) 3482 float log10(float x) @safe pure nothrow @nogc { return __ctfe ? cast(float) log10(cast(real) x) : log10Impl(x); } 3483 3484 // @@@DEPRECATED_[2.112.0]@@@ 3485 deprecated("`std.math.exponential.log10` called with argument types `(int)` matches both " 3486 ~ "`log10(real)`, `log10(double)`, and `log10(float)`. Cast argument to floating point type instead.") 3487 real log10(int x) @safe pure nothrow @nogc { return log10(cast(real) x); } 3488 // @@@DEPRECATED_[2.112.0]@@@ 3489 deprecated("`std.math.exponential.log10` called with argument types `(uint)` matches both " 3490 ~ "`log10(real)`, `log10(double)`, and `log10(float)`. Cast argument to floating point type instead.") 3491 real log10(uint x) @safe pure nothrow @nogc { return log10(cast(real) x); } 3492 // @@@DEPRECATED_[2.112.0]@@@ 3493 deprecated("`std.math.exponential.log10` called with argument types `(long)` matches both " 3494 ~ "`log10(real)`, `log10(double)`, and `log10(float)`. Cast argument to floating point type instead.") 3495 real log10(long x) @safe pure nothrow @nogc { return log10(cast(real) x); } 3496 // @@@DEPRECATED_[2.112.0]@@@ 3497 deprecated("`std.math.exponential.log10` called with argument types `(ulong)` matches both " 3498 ~ "`log10(real)`, `log10(double)`, and `log10(float)`. Cast argument to floating point type instead.") 3499 real log10(ulong x) @safe pure nothrow @nogc { return log10(cast(real) x); } 3500 3501 /// 3502 @safe pure nothrow @nogc unittest 3503 { 3504 import std.math.algebraic : fabs; 3505 3506 assert(fabs(log10(1000.0L) - 3) < .000001); 3507 } 3508 3509 @safe pure nothrow @nogc unittest 3510 { 3511 import std.math.algebraic : fabs; 3512 3513 assert(fabs(log10(1000.0) - 3) < .000001); 3514 assert(fabs(log10(1000.0f) - 3) < .000001); 3515 } 3516 3517 private T log10Impl(T)(T x) @safe pure nothrow @nogc 3518 { 3519 import std.math.constants : SQRT1_2; 3520 import std.math.algebraic : poly; 3521 import std.math.traits : isNaN, isInfinity, signbit; 3522 import std.math : floatTraits, RealFormat; 3523 3524 alias coeffs = LogCoeffs!T; 3525 alias F = floatTraits!T; 3526 3527 static if (F.realFormat == RealFormat.ieeeExtended || 3528 F.realFormat == RealFormat.ieeeExtended53 || 3529 F.realFormat == RealFormat.ieeeQuadruple) 3530 { 3531 // log10(2) split into two parts. 3532 enum T L102A = 0.3125L; 3533 enum T L102B = -1.14700043360188047862611052755069732318101185E-2L; 3534 3535 // log10(e) split into two parts. 3536 enum T L10EA = 0.5L; 3537 enum T L10EB = -6.570551809674817234887108108339491770560299E-2L; 3538 } 3539 else static if (F.realFormat == RealFormat.ieeeDouble || 3540 F.realFormat == RealFormat.ieeeSingle) 3541 { 3542 enum T L102A = 3.0078125E-1; 3543 enum T L102B = 2.48745663981195213739E-4; 3544 3545 enum T L10EA = 4.3359375E-1; 3546 enum T L10EB = 7.00731903251827651129E-4; 3547 } 3548 else 3549 static assert(0, "Not implemented for this architecture"); 3550 3551 // Special cases are the same as for log. 3552 if (isNaN(x)) 3553 return x; 3554 if (isInfinity(x) && !signbit(x)) 3555 return x; 3556 if (x == 0.0) 3557 return -T.infinity; 3558 if (x < 0.0) 3559 return T.nan; 3560 3561 // Separate mantissa from exponent. 3562 // Note, frexp is used so that denormal numbers will be handled properly. 3563 T y, z; 3564 int exp; 3565 3566 x = frexp(x, exp); 3567 3568 static if (F.realFormat == RealFormat.ieeeExtended || 3569 F.realFormat == RealFormat.ieeeExtended53 || 3570 F.realFormat == RealFormat.ieeeQuadruple) 3571 { 3572 // Logarithm using log(x) = z + z^^3 R(z) / S(z), 3573 // where z = 2(x - 1)/(x + 1) 3574 if ((exp > 2) || (exp < -2)) 3575 { 3576 if (x < SQRT1_2) 3577 { // 2(2x - 1)/(2x + 1) 3578 exp -= 1; 3579 z = x - 0.5; 3580 y = 0.5 * z + 0.5; 3581 } 3582 else 3583 { // 2(x - 1)/(x + 1) 3584 z = x - 0.5; 3585 z -= 0.5; 3586 y = 0.5 * x + 0.5; 3587 } 3588 x = z / y; 3589 z = x * x; 3590 y = x * (z * poly(z, coeffs.logR) / poly(z, coeffs.logS)); 3591 goto Ldone; 3592 } 3593 } 3594 3595 // Logarithm using log(1 + x) = x - .5x^^2 + x^^3 P(x) / Q(x) 3596 if (x < SQRT1_2) 3597 { 3598 exp -= 1; 3599 x = 2.0 * x - 1.0; 3600 } 3601 else 3602 x = x - 1.0; 3603 3604 z = x * x; 3605 static if (F.realFormat == RealFormat.ieeeSingle) 3606 y = x * (z * poly(x, coeffs.log10P)); 3607 else 3608 y = x * (z * poly(x, coeffs.log10P) / poly(x, coeffs.log10Q)); 3609 y = y - 0.5 * z; 3610 3611 // Multiply log of fraction by log10(e) and base 2 exponent by log10(2). 3612 // This sequence of operations is critical and it may be horribly 3613 // defeated by some compiler optimizers. 3614 Ldone: 3615 z = y * L10EB; 3616 z += x * L10EB; 3617 z += exp * L102B; 3618 z += y * L10EA; 3619 z += x * L10EA; 3620 z += exp * L102A; 3621 3622 return z; 3623 } 3624 3625 @safe @nogc nothrow unittest 3626 { 3627 import std.math : floatTraits, RealFormat; 3628 import std.meta : AliasSeq; 3629 3630 static void testLog10(T)(T[2][] vals) 3631 { 3632 import std.math.operations : isClose; 3633 import std.math.traits : isNaN; 3634 foreach (ref pair; vals) 3635 { 3636 if (isNaN(pair[1])) 3637 assert(isNaN(log10(pair[0]))); 3638 else 3639 assert(isClose(log10(pair[0]), pair[1])); 3640 } 3641 } 3642 static foreach (F; AliasSeq!(float, double, real)) 3643 {{ 3644 scope F[2][] vals = [ 3645 [F(1), F(0x0p+0)], [F(2), F(0x1.34413509f79fef32p-2)], 3646 [F(4), F(0x1.34413509f79fef32p-1)], [F(8), F(0x1.ce61cf8ef36fe6cap-1)], 3647 [F(16), F(0x1.34413509f79fef32p+0)], [F(32), F(0x1.8151824c7587eafep+0)], 3648 [F(64), F(0x1.ce61cf8ef36fe6cap+0)], [F(128), F(0x1.0db90e68b8abf14cp+1)], 3649 [F(256), F(0x1.34413509f79fef32p+1)], [F(512), F(0x1.5ac95bab3693ed18p+1)], 3650 [F(1024), F(0x1.8151824c7587eafep+1)], [F(2048), F(0x1.a7d9a8edb47be8e4p+1)], 3651 [F(3), F(0x1.e8927964fd5fd08cp-2)], [F(5), F(0x1.65df657b04300868p-1)], 3652 [F(7), F(0x1.b0b0b0b78cc3f296p-1)], [F(15), F(0x1.2d145116c16ff856p+0)], 3653 [F(17), F(0x1.3afeb354b7d9731ap+0)], [F(31), F(0x1.7dc9e145867e62eap+0)], 3654 [F(33), F(0x1.84bd545e4baeddp+0)], [F(63), F(0x1.cca1950e4511e192p+0)], 3655 [F(65), F(0x1.d01b16f9433cf7b8p+0)], [F(-0), -F.infinity], [F(0), -F.infinity], 3656 [F(0.1), F(-0x1p+0)], [F(0.25), F(-0x1.34413509f79fef32p-1)], 3657 [F(0.75), F(-0x1.ffbfc2bbc7803758p-4)], [F(0.875), F(-0x1.db11ed766abf432ep-5)], 3658 [F(10), F(0x1p+0)], [F(100), F(0x1p+1)], [F(10000), F(0x1p+2)], 3659 ]; 3660 testLog10(vals); 3661 }} 3662 { 3663 float[2][16] vals = [ 3664 [float.nan, float.nan],[-float.nan, float.nan], 3665 [float.infinity, float.infinity], [-float.infinity, float.nan], 3666 [float.min_normal, -0x1.2f703p+5f], [-float.min_normal, float.nan], 3667 [float.max, 0x1.344136p+5f], [-float.max, float.nan], 3668 [float.min_normal / 2, -0x1.31d8b2p+5f], [-float.min_normal / 2, float.nan], 3669 [float.max / 2, 0x1.31d8b2p+5f], [-float.max / 2, float.nan], 3670 [float.min_normal / 3, -0x1.334156p+5f], [-float.min_normal / 3, float.nan], 3671 [float.max / 3, 0x1.30701p+5f], [-float.max / 3, float.nan], 3672 ]; 3673 testLog10(vals); 3674 } 3675 { 3676 double[2][16] vals = [ 3677 [double.nan, double.nan],[-double.nan, double.nan], 3678 [double.infinity, double.infinity], [-double.infinity, double.nan], 3679 [double.min_normal, -0x1.33a7146f72a42p+8], [-double.min_normal, double.nan], 3680 [double.max, 0x1.34413509f79ffp+8], [-double.max, double.nan], 3681 [double.min_normal / 2, -0x1.33f424bcb522p+8], [-double.min_normal / 2, double.nan], 3682 [double.max / 2, 0x1.33f424bcb522p+8], [-double.max / 2, double.nan], 3683 [double.min_normal / 3, -0x1.3421390dcbe37p+8], [-double.min_normal / 3, double.nan], 3684 [double.max / 3, 0x1.33c7106b9e609p+8], [-double.max / 3, double.nan], 3685 ]; 3686 testLog10(vals); 3687 } 3688 alias F = floatTraits!real; 3689 static if (F.realFormat == RealFormat.ieeeExtended || F.realFormat == RealFormat.ieeeQuadruple) 3690 {{ 3691 real[2][16] vals = [ 3692 [real.nan, real.nan],[-real.nan, real.nan], 3693 [real.infinity, real.infinity], [-real.infinity, real.nan], 3694 [real.min_normal, -0x1.343793004f503232p+12L], [-real.min_normal, real.nan], 3695 [real.max, 0x1.34413509f79fef32p+12L], [-real.max, real.nan], 3696 [real.min_normal / 2, -0x1.343c6405237810b2p+12L], [-real.min_normal / 2, real.nan], 3697 [real.max / 2, 0x1.343c6405237810b2p+12L], [-real.max / 2, real.nan], 3698 [real.min_normal / 3, -0x1.343f354a34e427bp+12L], [-real.min_normal / 3, real.nan], 3699 [real.max / 3, 0x1.343992c0120bf9b2p+12L], [-real.max / 3, real.nan], 3700 ]; 3701 testLog10(vals); 3702 }} 3703 } 3704 3705 /** 3706 * Calculates the natural logarithm of 1 + x. 3707 * 3708 * For very small x, log1p(x) will be more accurate than 3709 * log(1 + x). 3710 * 3711 * $(TABLE_SV 3712 * $(TR $(TH x) $(TH log1p(x)) $(TH divide by 0?) $(TH invalid?)) 3713 * $(TR $(TD $(PLUSMN)0.0) $(TD $(PLUSMN)0.0) $(TD no) $(TD no)) 3714 * $(TR $(TD -1.0) $(TD -$(INFIN)) $(TD yes) $(TD no)) 3715 * $(TR $(TD $(LT)-1.0) $(TD -$(NAN)) $(TD no) $(TD yes)) 3716 * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) $(TD no) $(TD no)) 3717 * ) 3718 */ 3719 pragma(inline, true) 3720 real log1p(real x) @safe pure nothrow @nogc 3721 { 3722 version (INLINE_YL2X) 3723 { 3724 // On x87, yl2xp1 is valid if and only if -0.5 <= lg(x) <= 0.5, 3725 // ie if -0.29 <= x <= 0.414 3726 import std.math.constants : LN2; 3727 return (core.math.fabs(x) <= 0.25) ? core.math.yl2xp1(x, LN2) : core.math.yl2x(x+1, LN2); 3728 } 3729 else 3730 return log1pImpl(x); 3731 } 3732 3733 /// ditto 3734 pragma(inline, true) 3735 double log1p(double x) @safe pure nothrow @nogc { return __ctfe ? cast(double) log1p(cast(real) x) : log1pImpl(x); } 3736 3737 /// ditto 3738 pragma(inline, true) 3739 float log1p(float x) @safe pure nothrow @nogc { return __ctfe ? cast(float) log1p(cast(real) x) : log1pImpl(x); } 3740 3741 // @@@DEPRECATED_[2.112.0]@@@ 3742 deprecated("`std.math.exponential.log1p` called with argument types `(int)` matches both " 3743 ~ "`log1p(real)`, `log1p(double)`, and `log1p(float)`. Cast argument to floating point type instead.") 3744 real log1p(int x) @safe pure nothrow @nogc { return log1p(cast(real) x); } 3745 // @@@DEPRECATED_[2.112.0]@@@ 3746 deprecated("`std.math.exponential.log1p` called with argument types `(uint)` matches both " 3747 ~ "`log1p(real)`, `log1p(double)`, and `log1p(float)`. Cast argument to floating point type instead.") 3748 real log1p(uint x) @safe pure nothrow @nogc { return log1p(cast(real) x); } 3749 // @@@DEPRECATED_[2.112.0]@@@ 3750 deprecated("`std.math.exponential.log1p` called with argument types `(long)` matches both " 3751 ~ "`log1p(real)`, `log1p(double)`, and `log1p(float)`. Cast argument to floating point type instead.") 3752 real log1p(long x) @safe pure nothrow @nogc { return log1p(cast(real) x); } 3753 // @@@DEPRECATED_[2.112.0]@@@ 3754 deprecated("`std.math.exponential.log1p` called with argument types `(ulong)` matches both " 3755 ~ "`log1p(real)`, `log1p(double)`, and `log1p(float)`. Cast argument to floating point type instead.") 3756 real log1p(ulong x) @safe pure nothrow @nogc { return log1p(cast(real) x); } 3757 3758 /// 3759 @safe pure unittest 3760 { 3761 import std.math.traits : isIdentical, isNaN; 3762 import std.math.operations : feqrel; 3763 3764 assert(isIdentical(log1p(0.0), 0.0)); 3765 assert(log1p(1.0).feqrel(0.69314) > 16); 3766 3767 assert(log1p(-1.0) == -real.infinity); 3768 assert(isNaN(log1p(-2.0))); 3769 assert(log1p(real.nan) is real.nan); 3770 assert(log1p(-real.nan) is -real.nan); 3771 assert(log1p(real.infinity) == real.infinity); 3772 } 3773 3774 private T log1pImpl(T)(T x) @safe pure nothrow @nogc 3775 { 3776 import std.math.traits : isNaN, isInfinity, signbit; 3777 import std.math.algebraic : poly; 3778 import std.math.constants : SQRT1_2, SQRT2; 3779 import std.math : floatTraits, RealFormat; 3780 3781 // Special cases. 3782 if (isNaN(x) || x == 0.0) 3783 return x; 3784 if (isInfinity(x) && !signbit(x)) 3785 return x; 3786 if (x == -1.0) 3787 return -T.infinity; 3788 if (x < -1.0) 3789 return T.nan; 3790 3791 alias F = floatTraits!T; 3792 static if (F.realFormat == RealFormat.ieeeSingle || 3793 F.realFormat == RealFormat.ieeeDouble) 3794 { 3795 // When the input is within the range 1/sqrt(2) <= x+1 <= sqrt(2), compute 3796 // log1p inline. Forwarding to log() would otherwise result in inaccuracies. 3797 const T xp1 = x + 1.0; 3798 if (xp1 >= SQRT1_2 && xp1 <= SQRT2) 3799 { 3800 alias coeffs = LogCoeffs!T; 3801 3802 T px = poly(x, coeffs.logp1P); 3803 T qx = poly(x, coeffs.logp1Q); 3804 const T xx = x * x; 3805 qx = x + ((cast(T) -0.5) * xx + x * (xx * px / qx)); 3806 return qx; 3807 } 3808 } 3809 3810 return logImpl!(T, true)(x); 3811 } 3812 3813 @safe @nogc nothrow unittest 3814 { 3815 import std.math : floatTraits, RealFormat; 3816 import std.meta : AliasSeq; 3817 3818 static void testLog1p(T)(T[2][] vals) 3819 { 3820 import std.math.operations : isClose; 3821 import std.math.traits : isNaN; 3822 foreach (ref pair; vals) 3823 { 3824 if (isNaN(pair[1])) 3825 assert(isNaN(log1p(pair[0]))); 3826 else 3827 assert(isClose(log1p(pair[0]), pair[1])); 3828 } 3829 } 3830 static foreach (F; AliasSeq!(float, double, real)) 3831 {{ 3832 scope F[2][] vals = [ 3833 [F(1), F(0x1.62e42fefa39ef358p-1)], [F(2), F(0x1.193ea7aad030a976p+0)], 3834 [F(4), F(0x1.9c041f7ed8d336bp+0)], [F(8), F(0x1.193ea7aad030a976p+1)], 3835 [F(16), F(0x1.6aa6bc1fa7f79cfp+1)], [F(32), F(0x1.bf8d8f4d5b8d1038p+1)], 3836 [F(64), F(0x1.0b292939429755ap+2)], [F(128), F(0x1.37072a9b5b6cb31p+2)], 3837 [F(256), F(0x1.63241004e9010ad8p+2)], [F(512), F(0x1.8f60adf041bde2a8p+2)], 3838 [F(1024), F(0x1.bbad39ebe1cc08b6p+2)], [F(2048), F(0x1.e801c1698ba4395cp+2)], 3839 [F(3), F(0x1.62e42fefa39ef358p+0)], [F(5), F(0x1.cab0bfa2a2002322p+0)], 3840 [F(7), F(0x1.0a2b23f3bab73682p+1)], [F(15), F(0x1.62e42fefa39ef358p+1)], 3841 [F(17), F(0x1.71f7b3a6b918664cp+1)], [F(31), F(0x1.bb9d3beb8c86b02ep+1)], 3842 [F(33), F(0x1.c35fc81b90df59c6p+1)], [F(63), F(0x1.0a2b23f3bab73682p+2)], 3843 [F(65), F(0x1.0c234da4a23a6686p+2)], [F(-0), F(-0x0p+0)], [F(0), F(0x0p+0)], 3844 [F(0.1), F(0x1.8663f793c46c69cp-4)], [F(0.25), F(0x1.c8ff7c79a9a21ac4p-3)], 3845 [F(0.75), F(0x1.1e85f5e7040d03ep-1)], [F(0.875), F(0x1.41d8fe84672ae646p-1)], 3846 [F(10), F(0x1.32ee3b77f374bb7cp+1)], [F(100), F(0x1.275e2271bba30be4p+2)], 3847 [F(10000), F(0x1.26bbed6fbd84182ep+3)], 3848 ]; 3849 testLog1p(vals); 3850 }} 3851 { 3852 float[2][16] vals = [ 3853 [float.nan, float.nan],[-float.nan, float.nan], 3854 [float.infinity, float.infinity], [-float.infinity, float.nan], 3855 [float.min_normal, 0x1p-126f], [-float.min_normal, -0x1p-126f], 3856 [float.max, 0x1.62e43p+6f], [-float.max, float.nan], 3857 [float.min_normal / 2, 0x0.8p-126f], [-float.min_normal / 2, -0x0.8p-126f], 3858 [float.max / 2, 0x1.601e68p+6f], [-float.max / 2, float.nan], 3859 [float.min_normal / 3, 0x0.555556p-126f], [-float.min_normal / 3, -0x0.555556p-126f], 3860 [float.max / 3, 0x1.5e7f36p+6f], [-float.max / 3, float.nan], 3861 ]; 3862 testLog1p(vals); 3863 } 3864 { 3865 double[2][16] vals = [ 3866 [double.nan, double.nan],[-double.nan, double.nan], 3867 [double.infinity, double.infinity], [-double.infinity, double.nan], 3868 [double.min_normal, 0x1p-1022], [-double.min_normal, -0x1p-1022], 3869 [double.max, 0x1.62e42fefa39efp+9], [-double.max, double.nan], 3870 [double.min_normal / 2, 0x0.8p-1022], [-double.min_normal / 2, -0x0.8p-1022], 3871 [double.max / 2, 0x1.628b76e3a7b61p+9], [-double.max / 2, double.nan], 3872 [double.min_normal / 3, 0x0.5555555555555p-1022], [-double.min_normal / 3, -0x0.5555555555555p-1022], 3873 [double.max / 3, 0x1.6257909bce36ep+9], [-double.max / 3, double.nan], 3874 ]; 3875 testLog1p(vals); 3876 } 3877 alias F = floatTraits!real; 3878 static if (F.realFormat == RealFormat.ieeeExtended || F.realFormat == RealFormat.ieeeQuadruple) 3879 {{ 3880 real[2][16] vals = [ 3881 [real.nan, real.nan],[-real.nan, real.nan], 3882 [real.infinity, real.infinity], [-real.infinity, real.nan], 3883 [real.min_normal, 0x1p-16382L], [-real.min_normal, -0x1p-16382L], 3884 [real.max, 0x1.62e42fefa39ef358p+13L], [-real.max, real.nan], 3885 [real.min_normal / 2, 0x0.8p-16382L], [-real.min_normal / 2, -0x0.8p-16382L], 3886 [real.max / 2, 0x1.62dea45ee3e064dcp+13L], [-real.max / 2, real.nan], 3887 [real.min_normal / 3, 0x0.5555555555555556p-16382L], [-real.min_normal / 3, -0x0.5555555555555556p-16382L], 3888 [real.max / 3, 0x1.62db65fa664871d2p+13L], [-real.max / 3, real.nan], 3889 ]; 3890 testLog1p(vals); 3891 }} 3892 } 3893 3894 /*************************************** 3895 * Calculates the base-2 logarithm of x: 3896 * $(SUB log, 2)x 3897 * 3898 * $(TABLE_SV 3899 * $(TR $(TH x) $(TH log2(x)) $(TH divide by 0?) $(TH invalid?)) 3900 * $(TR $(TD $(PLUSMN)0.0) $(TD -$(INFIN)) $(TD yes) $(TD no) ) 3901 * $(TR $(TD $(LT)0.0) $(TD $(NAN)) $(TD no) $(TD yes) ) 3902 * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) $(TD no) $(TD no) ) 3903 * ) 3904 */ 3905 pragma(inline, true) 3906 real log2(real x) @safe pure nothrow @nogc 3907 { 3908 version (INLINE_YL2X) 3909 return core.math.yl2x(x, 1.0L); 3910 else 3911 return log2Impl(x); 3912 } 3913 3914 /// ditto 3915 pragma(inline, true) 3916 double log2(double x) @safe pure nothrow @nogc { return __ctfe ? cast(double) log2(cast(real) x) : log2Impl(x); } 3917 3918 /// ditto 3919 pragma(inline, true) 3920 float log2(float x) @safe pure nothrow @nogc { return __ctfe ? cast(float) log2(cast(real) x) : log2Impl(x); } 3921 3922 // @@@DEPRECATED_[2.112.0]@@@ 3923 deprecated("`std.math.exponential.log2` called with argument types `(int)` matches both " 3924 ~ "`log2(real)`, `log2(double)`, and `log2(float)`. Cast argument to floating point type instead.") 3925 real log2(int x) @safe pure nothrow @nogc { return log2(cast(real) x); } 3926 // @@@DEPRECATED_[2.112.0]@@@ 3927 deprecated("`std.math.exponential.log2` called with argument types `(uint)` matches both " 3928 ~ "`log2(real)`, `log2(double)`, and `log2(float)`. Cast argument to floating point type instead.") 3929 real log2(uint x) @safe pure nothrow @nogc { return log2(cast(real) x); } 3930 // @@@DEPRECATED_[2.112.0]@@@ 3931 deprecated("`std.math.exponential.log2` called with argument types `(long)` matches both " 3932 ~ "`log2(real)`, `log2(double)`, and `log2(float)`. Cast argument to floating point type instead.") 3933 real log2(long x) @safe pure nothrow @nogc { return log2(cast(real) x); } 3934 // @@@DEPRECATED_[2.112.0]@@@ 3935 deprecated("`std.math.exponential.log2` called with argument types `(ulong)` matches both " 3936 ~ "`log2(real)`, `log2(double)`, and `log2(float)`. Cast argument to floating point type instead.") 3937 real log2(ulong x) @safe pure nothrow @nogc { return log2(cast(real) x); } 3938 3939 /// 3940 @safe unittest 3941 { 3942 import std.math.operations : isClose; 3943 3944 assert(isClose(log2(1024.0L), 10)); 3945 } 3946 3947 @safe @nogc nothrow unittest 3948 { 3949 import std.math.operations : isClose; 3950 3951 // check if values are equal to 19 decimal digits of precision 3952 assert(isClose(log2(1024.0L), 10, 1e-18)); 3953 } 3954 3955 private T log2Impl(T)(T x) @safe pure nothrow @nogc 3956 { 3957 import std.math.traits : isNaN, isInfinity, signbit; 3958 import std.math.constants : SQRT1_2, LOG2E; 3959 import std.math.algebraic : poly; 3960 import std.math : floatTraits, RealFormat; 3961 3962 alias coeffs = LogCoeffs!T; 3963 alias F = floatTraits!T; 3964 3965 // Special cases are the same as for log. 3966 if (isNaN(x)) 3967 return x; 3968 if (isInfinity(x) && !signbit(x)) 3969 return x; 3970 if (x == 0.0) 3971 return -T.infinity; 3972 if (x < 0.0) 3973 return T.nan; 3974 3975 // Separate mantissa from exponent. 3976 // Note, frexp is used so that denormal numbers will be handled properly. 3977 T y, z; 3978 int exp; 3979 3980 x = frexp(x, exp); 3981 3982 static if (F.realFormat == RealFormat.ieeeDouble || 3983 F.realFormat == RealFormat.ieeeExtended || 3984 F.realFormat == RealFormat.ieeeExtended53 || 3985 F.realFormat == RealFormat.ieeeQuadruple) 3986 { 3987 // Logarithm using log(x) = z + z^^3 R(z) / S(z), 3988 // where z = 2(x - 1)/(x + 1) 3989 if ((exp > 2) || (exp < -2)) 3990 { 3991 if (x < SQRT1_2) 3992 { // 2(2x - 1)/(2x + 1) 3993 exp -= 1; 3994 z = x - 0.5; 3995 y = 0.5 * z + 0.5; 3996 } 3997 else 3998 { // 2(x - 1)/(x + 1) 3999 z = x - 0.5; 4000 z -= 0.5; 4001 y = 0.5 * x + 0.5; 4002 } 4003 x = z / y; 4004 z = x * x; 4005 y = x * (z * poly(z, coeffs.logR) / poly(z, coeffs.logS)); 4006 goto Ldone; 4007 } 4008 } 4009 4010 // Logarithm using log(1 + x) = x - .5x^^2 + x^^3 P(x) / Q(x) 4011 if (x < SQRT1_2) 4012 { 4013 exp -= 1; 4014 x = 2.0 * x - 1.0; 4015 } 4016 else 4017 x = x - 1.0; 4018 4019 z = x * x; 4020 static if (F.realFormat == RealFormat.ieeeSingle) 4021 y = x * (z * poly(x, coeffs.log2P)); 4022 else 4023 y = x * (z * poly(x, coeffs.log2P) / poly(x, coeffs.log2Q)); 4024 y = y - 0.5 * z; 4025 4026 // Multiply log of fraction by log10(e) and base 2 exponent by log10(2). 4027 // This sequence of operations is critical and it may be horribly 4028 // defeated by some compiler optimizers. 4029 Ldone: 4030 z = y * (LOG2E - 1.0); 4031 z += x * (LOG2E - 1.0); 4032 z += y; 4033 z += x; 4034 z += exp; 4035 4036 return z; 4037 } 4038 4039 @safe @nogc nothrow unittest 4040 { 4041 import std.math : floatTraits, RealFormat; 4042 import std.meta : AliasSeq; 4043 4044 static void testLog2(T)(T[2][] vals) 4045 { 4046 import std.math.operations : isClose; 4047 import std.math.traits : isNaN; 4048 foreach (ref pair; vals) 4049 { 4050 if (isNaN(pair[1])) 4051 assert(isNaN(log2(pair[0]))); 4052 else 4053 assert(isClose(log2(pair[0]), pair[1])); 4054 } 4055 } 4056 static foreach (F; AliasSeq!(float, double, real)) 4057 {{ 4058 scope F[2][] vals = [ 4059 [F(1), F(0x0p+0)], [F(2), F(0x1p+0)], 4060 [F(4), F(0x1p+1)], [F(8), F(0x1.8p+1)], 4061 [F(16), F(0x1p+2)], [F(32), F(0x1.4p+2)], 4062 [F(64), F(0x1.8p+2)], [F(128), F(0x1.cp+2)], 4063 [F(256), F(0x1p+3)], [F(512), F(0x1.2p+3)], 4064 [F(1024), F(0x1.4p+3)], [F(2048), F(0x1.6p+3)], 4065 [F(3), F(0x1.95c01a39fbd687ap+0)], [F(5), F(0x1.2934f0979a3715fcp+1)], 4066 [F(7), F(0x1.675767f54042cd9ap+1)], [F(15), F(0x1.f414fdb4982259ccp+1)], 4067 [F(17), F(0x1.0598fdbeb244c5ap+2)], [F(31), F(0x1.3d118d66c4d4e554p+2)], 4068 [F(33), F(0x1.42d75a6eb1dfb0e6p+2)], [F(63), F(0x1.7e8bc1179e0caa9cp+2)], 4069 [F(65), F(0x1.816e79685c2d2298p+2)], [F(-0), -F.infinity], [F(0), -F.infinity], 4070 [F(0.1), F(-0x1.a934f0979a3715fcp+1)], [F(0.25), F(-0x1p+1)], 4071 [F(0.75), F(-0x1.a8ff971810a5e182p-2)], [F(0.875), F(-0x1.8a8980abfbd32668p-3)], 4072 [F(10), F(0x1.a934f0979a3715fcp+1)], [F(100), F(0x1.a934f0979a3715fcp+2)], 4073 [F(10000), F(0x1.a934f0979a3715fcp+3)], 4074 ]; 4075 testLog2(vals); 4076 }} 4077 { 4078 float[2][16] vals = [ 4079 [float.nan, float.nan],[-float.nan, float.nan], 4080 [float.infinity, float.infinity], [-float.infinity, float.nan], 4081 [float.min_normal, -0x1.f8p+6f], [-float.min_normal, float.nan], 4082 [float.max, 0x1p+7f], [-float.max, float.nan], 4083 [float.min_normal / 2, -0x1.fcp+6f], [-float.min_normal / 2, float.nan], 4084 [float.max / 2, 0x1.fcp+6f], [-float.max / 2, float.nan], 4085 [float.min_normal / 3, -0x1.fe57p+6f], [-float.min_normal / 3, float.nan], 4086 [float.max / 3, 0x1.f9a9p+6f], [-float.max / 3, float.nan], 4087 ]; 4088 testLog2(vals); 4089 } 4090 { 4091 double[2][16] vals = [ 4092 [double.nan, double.nan],[-double.nan, double.nan], 4093 [double.infinity, double.infinity], [-double.infinity, double.nan], 4094 [double.min_normal, -0x1.ffp+9], [-double.min_normal, double.nan], 4095 [double.max, 0x1p+10], [-double.max, double.nan], 4096 [double.min_normal / 2, -0x1.ff8p+9], [-double.min_normal / 2, double.nan], 4097 [double.max / 2, 0x1.ff8p+9], [-double.max / 2, double.nan], 4098 [double.min_normal / 3, -0x1.ffcae00d1cfdfp+9], [-double.min_normal / 3, double.nan], 4099 [double.max / 3, 0x1.ff351ff2e3021p+9], [-double.max / 3, double.nan], 4100 ]; 4101 testLog2(vals); 4102 } 4103 alias F = floatTraits!real; 4104 static if (F.realFormat == RealFormat.ieeeExtended || F.realFormat == RealFormat.ieeeQuadruple) 4105 {{ 4106 real[2][16] vals = [ 4107 [real.nan, real.nan],[-real.nan, real.nan], 4108 [real.infinity, real.infinity], [-real.infinity, real.nan], 4109 [real.min_normal, -0x1.fffp+13L], [-real.min_normal, real.nan], 4110 [real.max, 0x1p+14L], [-real.max, real.nan], 4111 [real.min_normal / 2, -0x1.fff8p+13L], [-real.min_normal / 2, real.nan], 4112 [real.max / 2, 0x1.fff8p+13L], [-real.max / 2, real.nan], 4113 [real.min_normal / 3, -0x1.fffcae00d1cfdeb4p+13L], [-real.min_normal / 3, real.nan], 4114 [real.max / 3, 0x1.fff351ff2e30214cp+13L], [-real.max / 3, real.nan], 4115 ]; 4116 testLog2(vals); 4117 }} 4118 } 4119 4120 /***************************************** 4121 * Extracts the exponent of x as a signed integral value. 4122 * 4123 * If x is subnormal, it is treated as if it were normalized. 4124 * For a positive, finite x: 4125 * 4126 * 1 $(LT)= $(I x) * FLT_RADIX$(SUPERSCRIPT -logb(x)) $(LT) FLT_RADIX 4127 * 4128 * $(TABLE_SV 4129 * $(TR $(TH x) $(TH logb(x)) $(TH divide by 0?) ) 4130 * $(TR $(TD $(PLUSMN)$(INFIN)) $(TD +$(INFIN)) $(TD no)) 4131 * $(TR $(TD $(PLUSMN)0.0) $(TD -$(INFIN)) $(TD yes) ) 4132 * ) 4133 */ 4134 pragma(inline, true) 4135 real logb(real x) @trusted pure nothrow @nogc 4136 { 4137 version (InlineAsm_X87_MSVC) 4138 return logbAsm(x); 4139 else 4140 return logbImpl(x); 4141 } 4142 4143 /// ditto 4144 pragma(inline, true) 4145 double logb(double x) @trusted pure nothrow @nogc { return logbImpl(x); } 4146 4147 /// ditto 4148 pragma(inline, true) 4149 float logb(float x) @trusted pure nothrow @nogc { return logbImpl(x); } 4150 4151 /// 4152 @safe @nogc nothrow unittest 4153 { 4154 assert(logb(1.0) == 0); 4155 assert(logb(100.0) == 6); 4156 4157 assert(logb(0.0) == -real.infinity); 4158 assert(logb(real.infinity) == real.infinity); 4159 assert(logb(-real.infinity) == real.infinity); 4160 } 4161 4162 @safe @nogc nothrow unittest 4163 { 4164 import std.meta : AliasSeq; 4165 import std.typecons : Tuple; 4166 import std.math.traits : isNaN; 4167 static foreach (F; AliasSeq!(float, double, real)) 4168 {{ 4169 alias T = Tuple!(F, F); 4170 T[17] vals = // x, logb(x) 4171 [ 4172 T(1.0 , 0 ), 4173 T(100.0 , 6 ), 4174 T(0.0 , -F.infinity), 4175 T(-0.0 , -F.infinity), 4176 T(1024 , 10 ), 4177 T(-2000 , 10 ), 4178 T(0x0.1p-127 , -131 ), 4179 T(0x0.01p-127 , -135 ), 4180 T(0x0.011p-127 , -135 ), 4181 T(F.nan , F.nan ), 4182 T(-F.nan , F.nan ), 4183 T(F.infinity , F.infinity ), 4184 T(-F.infinity , F.infinity ), 4185 T(F.min_normal , F.min_exp-1), 4186 T(-F.min_normal, F.min_exp-1), 4187 T(F.max , F.max_exp-1), 4188 T(-F.max , F.max_exp-1), 4189 ]; 4190 4191 foreach (elem; vals) 4192 { 4193 if (isNaN(elem[1])) 4194 assert(isNaN(logb(elem[1]))); 4195 else 4196 assert(logb(elem[0]) == elem[1]); 4197 } 4198 }} 4199 } 4200 4201 version (InlineAsm_X87_MSVC) 4202 private T logbAsm(T)(T x) @trusted pure nothrow @nogc 4203 { 4204 version (X86_64) 4205 { 4206 asm pure nothrow @nogc 4207 { 4208 naked ; 4209 fld real ptr [RCX] ; 4210 fxtract ; 4211 fstp ST(0) ; 4212 ret ; 4213 } 4214 } 4215 else 4216 { 4217 asm pure nothrow @nogc 4218 { 4219 fld x ; 4220 fxtract ; 4221 fstp ST(0) ; 4222 } 4223 } 4224 } 4225 4226 private T logbImpl(T)(T x) @trusted pure nothrow @nogc 4227 { 4228 import std.math.traits : isFinite; 4229 4230 // Handle special cases. 4231 if (!isFinite(x)) 4232 return x * x; 4233 if (x == 0) 4234 return -1 / (x * x); 4235 4236 return ilogb(x); 4237 } 4238 4239 @safe @nogc nothrow unittest 4240 { 4241 import std.math : floatTraits, RealFormat; 4242 import std.meta : AliasSeq; 4243 4244 static void testLogb(T)(T[2][] vals) 4245 { 4246 import std.math.operations : isClose; 4247 import std.math.traits : isNaN; 4248 foreach (ref pair; vals) 4249 { 4250 if (isNaN(pair[1])) 4251 assert(isNaN(logb(pair[0]))); 4252 else 4253 assert(isClose(logb(pair[0]), pair[1])); 4254 } 4255 } 4256 static foreach (F; AliasSeq!(float, double, real)) 4257 {{ 4258 scope F[2][] vals = [ 4259 [F(1), F(0x0p+0)], [F(2), F(0x1p+0)], 4260 [F(4), F(0x1p+1)], [F(8), F(0x1.8p+1)], 4261 [F(16), F(0x1p+2)], [F(32), F(0x1.4p+2)], 4262 [F(64), F(0x1.8p+2)], [F(128), F(0x1.cp+2)], 4263 [F(256), F(0x1p+3)], [F(512), F(0x1.2p+3)], 4264 [F(1024), F(0x1.4p+3)], [F(2048), F(0x1.6p+3)], 4265 [F(3), F(0x1p+0)], [F(5), F(0x1p+1)], 4266 [F(7), F(0x1p+1)], [F(15), F(0x1.8p+1)], 4267 [F(17), F(0x1p+2)], [F(31), F(0x1p+2)], 4268 [F(33), F(0x1.4p+2)], [F(63), F(0x1.4p+2)], 4269 [F(65), F(0x1.8p+2)], [F(-0), -F.infinity], [F(0), -F.infinity], 4270 [F(0.1), F(-0x1p+2)], [F(0.25), F(-0x1p+1)], 4271 [F(0.75), F(-0x1p+0)], [F(0.875), F(-0x1p+0)], 4272 [F(10), F(0x1.8p+1)], [F(100), F(0x1.8p+2)], 4273 [F(10000), F(0x1.ap+3)], 4274 ]; 4275 testLogb(vals); 4276 }} 4277 { 4278 float[2][16] vals = [ 4279 [float.nan, float.nan],[-float.nan, float.nan], 4280 [float.infinity, float.infinity], [-float.infinity, float.infinity], 4281 [float.min_normal, -0x1.f8p+6f], [-float.min_normal, -0x1.f8p+6f], 4282 [float.max, 0x1.fcp+6f], [-float.max, 0x1.fcp+6f], 4283 [float.min_normal / 2, -0x1.fcp+6f], [-float.min_normal / 2, -0x1.fcp+6f], 4284 [float.max / 2, 0x1.f8p+6f], [-float.max / 2, 0x1.f8p+6f], 4285 [float.min_normal / 3, -0x1p+7f], [-float.min_normal / 3, -0x1p+7f], 4286 [float.max / 3, 0x1.f8p+6f], [-float.max / 3, 0x1.f8p+6f], 4287 ]; 4288 testLogb(vals); 4289 } 4290 { 4291 double[2][16] vals = [ 4292 [double.nan, double.nan],[-double.nan, double.nan], 4293 [double.infinity, double.infinity], [-double.infinity, double.infinity], 4294 [double.min_normal, -0x1.ffp+9], [-double.min_normal, -0x1.ffp+9], 4295 [double.max, 0x1.ff8p+9], [-double.max, 0x1.ff8p+9], 4296 [double.min_normal / 2, -0x1.ff8p+9], [-double.min_normal / 2, -0x1.ff8p+9], 4297 [double.max / 2, 0x1.ffp+9], [-double.max / 2, 0x1.ffp+9], 4298 [double.min_normal / 3, -0x1p+10], [-double.min_normal / 3, -0x1p+10], 4299 [double.max / 3, 0x1.ffp+9], [-double.max / 3, 0x1.ffp+9], 4300 ]; 4301 testLogb(vals); 4302 } 4303 alias F = floatTraits!real; 4304 static if (F.realFormat == RealFormat.ieeeExtended || F.realFormat == RealFormat.ieeeQuadruple) 4305 {{ 4306 real[2][16] vals = [ 4307 [real.nan, real.nan],[-real.nan, real.nan], 4308 [real.infinity, real.infinity], [-real.infinity, real.infinity], 4309 [real.min_normal, -0x1.fffp+13L], [-real.min_normal, -0x1.fffp+13L], 4310 [real.max, 0x1.fff8p+13L], [-real.max, 0x1.fff8p+13L], 4311 [real.min_normal / 2, -0x1.fff8p+13L], [-real.min_normal / 2, -0x1.fff8p+13L], 4312 [real.max / 2, 0x1.fffp+13L], [-real.max / 2, 0x1.fffp+13L], 4313 [real.min_normal / 3, -0x1p+14L], [-real.min_normal / 3, -0x1p+14L], 4314 [real.max / 3, 0x1.fffp+13L], [-real.max / 3, 0x1.fffp+13L], 4315 ]; 4316 testLogb(vals); 4317 }} 4318 } 4319 4320 /************************************* 4321 * Efficiently calculates x * 2$(SUPERSCRIPT n). 4322 * 4323 * scalbn handles underflow and overflow in 4324 * the same fashion as the basic arithmetic operators. 4325 * 4326 * $(TABLE_SV 4327 * $(TR $(TH x) $(TH scalb(x))) 4328 * $(TR $(TD $(PLUSMNINF)) $(TD $(PLUSMNINF)) ) 4329 * $(TR $(TD $(PLUSMN)0.0) $(TD $(PLUSMN)0.0) ) 4330 * ) 4331 */ 4332 pragma(inline, true) 4333 real scalbn(real x, int n) @safe pure nothrow @nogc { return _scalbn(x,n); } 4334 4335 /// ditto 4336 pragma(inline, true) 4337 double scalbn(double x, int n) @safe pure nothrow @nogc { return _scalbn(x,n); } 4338 4339 /// ditto 4340 pragma(inline, true) 4341 float scalbn(float x, int n) @safe pure nothrow @nogc { return _scalbn(x,n); } 4342 4343 /// 4344 @safe pure nothrow @nogc unittest 4345 { 4346 assert(scalbn(0x1.2345678abcdefp0L, 999) == 0x1.2345678abcdefp999L); 4347 assert(scalbn(-real.infinity, 5) == -real.infinity); 4348 assert(scalbn(2.0,10) == 2048.0); 4349 assert(scalbn(2048.0f,-10) == 2.0f); 4350 } 4351 4352 pragma(inline, true) 4353 private F _scalbn(F)(F x, int n) 4354 { 4355 import std.math.traits : isInfinity; 4356 4357 if (__ctfe) 4358 { 4359 // Handle special cases. 4360 if (x == F(0.0) || isInfinity(x)) 4361 return x; 4362 } 4363 return core.math.ldexp(x, n); 4364 } 4365 4366 @safe pure nothrow @nogc unittest 4367 { 4368 // CTFE-able test 4369 static assert(scalbn(0x1.2345678abcdefp0L, 999) == 0x1.2345678abcdefp999L); 4370 static assert(scalbn(-real.infinity, 5) == -real.infinity); 4371 // Test with large exponent delta n where the result is in bounds but 2.0L ^^ n is not. 4372 enum initialExponent = real.min_exp + 2, resultExponent = real.max_exp - 2; 4373 enum int n = resultExponent - initialExponent; 4374 enum real x = 0x1.2345678abcdefp0L * (2.0L ^^ initialExponent); 4375 enum staticResult = scalbn(x, n); 4376 static assert(staticResult == 0x1.2345678abcdefp0L * (2.0L ^^ resultExponent)); 4377 assert(scalbn(x, n) == staticResult); 4378 } 4379