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