1 // Written in the D programming language.
4 This is a submodule of $(MREF std, math).
6 It contains several exponential and logarithm functions.
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
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)
22 TABLE_SV = <table border="1" cellpadding="4" cellspacing="0">
23 <caption>Special Values</caption>
28 PLUSMNINF = ±∞
33 module std
.math
.exponential
;
35 import std
.traits
: isFloatingPoint
, isIntegral
, isSigned
, isUnsigned
, Largest
, Unqual
;
37 static import core
.math
;
38 static import core
.stdc
.math
;
42 version (OSX
) { } // macOS 13 (M1) has issues emulating instruction
43 else version = INLINE_YL2X
; // x87 has opcodes for these
46 version (D_InlineAsm_X86
) version = InlineAsm_X86_Any
;
47 version (D_InlineAsm_X86_64
) version = InlineAsm_X86_Any
;
49 version (InlineAsm_X86_Any
) version = InlineAsm_X87
;
50 version (InlineAsm_X87
)
52 static assert(real.mant_dig
== 64);
53 version (CRuntime_Microsoft
) version = InlineAsm_X87_MSVC
;
58 // FloatingPointControl.clearExceptions() depends on version IeeeFlagsSupport
59 version (IeeeFlagsSupport
) version = FloatingPointControlSupport
;
63 * Compute the value of x $(SUPERSCRIPT n), where n is an integer
65 Unqual
!F
pow(F
, G
)(F x
, G n
) @nogc @trusted pure nothrow
66 if (isFloatingPoint
!(F
) && isIntegral
!(G
))
68 import std
.traits
: Unsigned
;
70 real p
= 1.0, v
= void;
71 Unsigned
!(Unqual
!G
) m
= n
;
75 if (n
== -1) return 1 / x
;
77 m
= cast(typeof(m
))(0 - n
);
109 @safe pure nothrow @nogc unittest
111 import std
.math
.operations
: feqrel
;
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
);
119 @safe pure nothrow @nogc unittest
121 import std
.math
.operations
: isClose
, feqrel
;
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;
133 immutable int neg1
= -1;
134 immutable short neg2
= -2;
135 immutable byte neg3
= -3;
136 immutable long neg8
= -8;
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
));
145 assert(pow(x
, neg1
) == 1 / x
);
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));
150 assert(feqrel(pow(x
, neg3
), 1 / (x
* x
* x
)) >= real.mant_dig
- 1);
153 @safe @nogc nothrow unittest
155 import std
.math
.operations
: isClose
;
157 assert(isClose(pow(2.0L, 10L), 1024, 1e-18));
160 // https://issues.dlang.org/show_bug.cgi?id=21601
161 @safe @nogc nothrow pure unittest
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
166 static if (real.mant_dig
>= 64)
168 // expected result: 3.790e-42
169 assert(pow(-513645318757045764096.0f, -2) > 0.0);
171 // expected result: 3.763915357831797e-309
172 assert(pow(-1.6299717435255677e+154, -2) > 0.0);
176 @safe @nogc nothrow unittest
178 import std
.math
.operations
: isClose
;
179 import std
.math
.traits
: isInfinity
;
181 static float f1
= 19100.0f;
182 static float f2
= 0.000012f;
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
));
189 static double d1
= 21800.0;
190 static double d2
= 0.000012;
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
));
197 static if (real.mant_dig
== 64) // x87
199 static real r1
= 21950.0L;
200 static real r2
= 0.000011L;
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
));
209 @safe @nogc nothrow pure unittest
211 import std
.math
.operations
: isClose
;
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
));
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
));
229 static if (real.mant_dig
== 64) // x87
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
));
242 * Compute the power of two integral numbers.
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.
253 * If both x and n are 0, the result is 1.
256 * If x is 0 and n is negative, the result is the same as the result of a
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
))
262 import std
.traits
: isSigned
;
264 typeof(return) p
, v
= void;
267 static if (isSigned
!(F
))
269 if (x
== -1) return cast(typeof(return)) (m
& 1 ?
-1 : 1);
271 static if (isSigned
!(G
))
273 if (x
== 0 && m
<= -1) return x
/ 0;
275 if (x
== 1) return 1;
276 static if (isSigned
!(G
))
313 @safe pure nothrow @nogc unittest
315 assert(pow(2, 3) == 8);
316 assert(pow(3, 2) == 9);
318 assert(pow(2, 10) == 1_024);
319 assert(pow(2, 20) == 1_048_576);
320 assert(pow(2, 30) == 1_073_741_824);
322 assert(pow(0, 0) == 1);
324 assert(pow(1, -5) == 1);
325 assert(pow(1, -6) == 1);
326 assert(pow(-1, -5) == -1);
327 assert(pow(-1, -6) == 1);
329 assert(pow(-2, 5) == -32);
330 assert(pow(-2, -5) == 0);
331 assert(pow(cast(double) -2, -5) == -0.03125);
334 @safe pure nothrow @nogc unittest
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;
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);
350 // https://issues.dlang.org/show_bug.cgi?id=7006
351 @safe pure nothrow @nogc unittest
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);
360 assert(pow(4294967290UL,2) == 18446744022169944100UL);
361 assert(pow(0,uint.max
) == 0);
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
)
368 return pow(cast(real) x
, cast(Unqual
!F
) y
);
372 @safe pure nothrow @nogc unittest
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
);
381 * Calculates x$(SUPERSCRIPT y).
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))
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) )
422 Unqual
!(Largest
!(F
, G
)) pow(F
, G
)(F x
, G y
) @nogc @trusted pure nothrow
423 if (isFloatingPoint
!(F
) && isFloatingPoint
!(G
))
425 return _powImpl(x
, y
);
429 @safe pure nothrow @nogc unittest
431 import std
.math
.operations
: isClose
;
433 assert(isClose(pow(2.0, 3.0), 8.0));
434 assert(isClose(pow(1.5, 10.0), 57.6650390625));
437 assert(isClose(pow(9.0, 0.5), 3.0));
439 assert(isClose(pow(1024.0, 0.1), 2.0));
441 assert(isClose(pow(-4.0, 3.0), -64.0));
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));
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));
454 // reciprocal of square root of 4
455 assert(isClose(pow(4.0, -0.5), 0.5));
458 assert(isClose(pow(0.0, 0.0), 1.0));
462 @safe pure nothrow @nogc unittest
464 import std
.math
.operations
: isClose
;
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)));
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));
481 @safe pure nothrow @nogc unittest
483 import std
.math
.traits
: isNaN
;
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
)));
503 @safe @nogc nothrow unittest
505 import std
.math
.operations
: isClose
;
507 assert(isClose(pow(2.0L, 10.0L), 1024, 1e-18));
510 @safe pure nothrow @nogc unittest
512 import std
.math
.operations
: isClose
;
513 import std
.math
.traits
: isIdentical
, isNaN
;
514 import std
.math
.constants
: PI
;
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
;
528 assert(pow(fnan
, zero
) == 1);
529 assert(pow(dnan
, zero
) == 1);
530 assert(pow(rnan
, zero
) == 1);
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));
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)));
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));
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);
572 // Now, actual numbers.
573 assert(isClose(pow(two
, three
), 8.0));
574 assert(isClose(pow(two
, -2.5), 0.1767766953));
576 // Test integer to float power.
577 immutable uint twoI
= 2;
578 assert(isClose(pow(twoI
, three
), 8.0));
581 // https://issues.dlang.org/show_bug.cgi?id=20508
582 @safe pure nothrow @nogc unittest
584 import std
.math
.traits
: isNaN
;
586 assert(isNaN(pow(-double.infinity
, 0.5)));
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);
595 private real _powImpl(real x
, real y
) @safe @nogc pure nothrow
598 import core
.math
: fabs, sqrt
;
599 import std
.math
.traits
: isInfinity
, isNaN
, signbit
;
604 if (isNaN(x
) && y
!= 0.0)
617 if (!signbit(y
) && !signbit(x
))
622 else if (fabs(x
) > 1)
629 else if (fabs(x
) == 1)
645 long i
= cast(long) y
;
678 long i
= cast(long) y
;
707 if ((x
> 0.0 && x
< 1.0) ||
(x
> -1.0 && x
< 0.0))
709 if (x
> 1.0 || x
< -1.0)
714 if ((x
> 0.0 && x
< 1.0) ||
(x
> -1.0 && x
< 0.0))
716 if (x
> 1.0 || x
< -1.0)
729 long i
= cast(long) y
;
746 // Integer power of x.
747 long iy
= cast(long) y
;
748 if (iy
== y
&& fabs(y
) < 32_768.0)
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
)
759 // Generic method, for any FP type
760 import std
.math
.rounding
: floor
;
762 return sqrt(x
); // Complex result -- create a NaN
770 // Much faster, if ulong has enough precision
771 const absY
= fabs(y
);
774 const uy
= cast(ulong) absY
;
776 return sqrt(x
); // Complex result -- create a NaN
784 version (INLINE_YL2X
)
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
) );
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
));
805 /** Computes the value of a positive integer `x`, raised to the power `n`, modulo `m`.
813 * `x` to the power `n`, modulo `m`.
814 * The return type is the largest of `x`'s and `m`'s type.
816 * The function requires that all values have unsigned types.
818 Unqual
!(Largest
!(F
, H
)) powmod(F
, G
, H
)(F x
, G n
, H m
)
819 if (isUnsigned
!F
&& isUnsigned
!G
&& isUnsigned
!H
)
821 import std
.meta
: AliasSeq
;
823 alias T
= Unqual
!(Largest
!(F
, H
));
824 static if (T
.sizeof
<= 4)
826 alias DoubleT
= AliasSeq
!(void, ushort, uint, void, ulong)[T
.sizeof
];
829 static T
mulmod(T a
, T b
, T c
)
831 static if (T
.sizeof
== 8)
833 static T
addmod(T a
, T b
, T c
)
848 result
= addmod(result
, b
, c
);
858 DoubleT result
= cast(DoubleT
) (cast(DoubleT
) a
* cast(DoubleT
) b
);
863 T base
= x
, result
= 1, modulus
= m
;
864 Unqual
!G exponent
= n
;
869 result
= mulmod(result
, base
, modulus
);
871 base
= mulmod(base
, base
, modulus
);
879 @safe pure nothrow @nogc unittest
881 assert(powmod(1U, 10U, 3U) == 1);
882 assert(powmod(3U, 2U, 6U) == 3);
883 assert(powmod(5U, 5U, 15U) == 5);
884 assert(powmod(2U, 3U, 5U) == 3);
885 assert(powmod(2U, 4U, 5U) == 1);
886 assert(powmod(2U, 5U, 5U) == 2);
889 @safe pure nothrow @nogc unittest
891 ulong a
= 18446744073709551615u, b
= 20u, c
= 18446744073709551610u;
892 assert(powmod(a
, b
, c
) == 95367431640625u);
893 a
= 100; b
= 7919; c
= 18446744073709551557u;
894 assert(powmod(a
, b
, c
) == 18223853583554725198u);
895 a
= 117; b
= 7919; c
= 18446744073709551557u;
896 assert(powmod(a
, b
, c
) == 11493139548346411394u);
897 a
= 134; b
= 7919; c
= 18446744073709551557u;
898 assert(powmod(a
, b
, c
) == 10979163786734356774u);
899 a
= 151; b
= 7919; c
= 18446744073709551557u;
900 assert(powmod(a
, b
, c
) == 7023018419737782840u);
901 a
= 168; b
= 7919; c
= 18446744073709551557u;
902 assert(powmod(a
, b
, c
) == 58082701842386811u);
903 a
= 185; b
= 7919; c
= 18446744073709551557u;
904 assert(powmod(a
, b
, c
) == 17423478386299876798u);
905 a
= 202; b
= 7919; c
= 18446744073709551557u;
906 assert(powmod(a
, b
, c
) == 5522733478579799075u);
907 a
= 219; b
= 7919; c
= 18446744073709551557u;
908 assert(powmod(a
, b
, c
) == 15230218982491623487u);
909 a
= 236; b
= 7919; c
= 18446744073709551557u;
910 assert(powmod(a
, b
, c
) == 5198328724976436000u);
912 a
= 0; b
= 7919; c
= 18446744073709551557u;
913 assert(powmod(a
, b
, c
) == 0);
914 a
= 123; b
= 0; c
= 18446744073709551557u;
915 assert(powmod(a
, b
, c
) == 1);
917 immutable ulong a1
= 253, b1
= 7919, c1
= 18446744073709551557u;
918 assert(powmod(a1
, b1
, c1
) == 3883707345459248860u);
920 uint x
= 100 ,y
= 7919, z
= 1844674407u;
921 assert(powmod(x
, y
, z
) == 1613100340u);
922 x
= 134; y
= 7919; z
= 1844674407u;
923 assert(powmod(x
, y
, z
) == 734956622u);
924 x
= 151; y
= 7919; z
= 1844674407u;
925 assert(powmod(x
, y
, z
) == 1738696945u);
926 x
= 168; y
= 7919; z
= 1844674407u;
927 assert(powmod(x
, y
, z
) == 1247580927u);
928 x
= 185; y
= 7919; z
= 1844674407u;
929 assert(powmod(x
, y
, z
) == 1293855176u);
930 x
= 202; y
= 7919; z
= 1844674407u;
931 assert(powmod(x
, y
, z
) == 1566963682u);
932 x
= 219; y
= 7919; z
= 1844674407u;
933 assert(powmod(x
, y
, z
) == 181227807u);
934 x
= 236; y
= 7919; z
= 1844674407u;
935 assert(powmod(x
, y
, z
) == 217988321u);
936 x
= 253; y
= 7919; z
= 1844674407u;
937 assert(powmod(x
, y
, z
) == 1588843243u);
939 x
= 0; y
= 7919; z
= 184467u;
940 assert(powmod(x
, y
, z
) == 0);
941 x
= 123; y
= 0; z
= 1844674u;
942 assert(powmod(x
, y
, z
) == 1);
944 immutable ubyte x1
= 117;
945 immutable uint y1
= 7919;
946 immutable uint z1
= 1844674407u;
947 auto res
= powmod(x1
, y1
, z1
);
948 assert(is(typeof(res
) == uint));
949 assert(res
== 9479781u);
951 immutable ushort x2
= 123;
952 immutable uint y2
= 203;
953 immutable ubyte z2
= 113;
954 auto res2
= powmod(x2
, y2
, z2
);
955 assert(is(typeof(res2
) == ushort));
960 * Calculates e$(SUPERSCRIPT x).
963 * $(TR $(TH x) $(TH e$(SUPERSCRIPT x)) )
964 * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) )
965 * $(TR $(TD -$(INFIN)) $(TD +0.0) )
966 * $(TR $(TD $(NAN)) $(TD $(NAN)) )
970 real exp(real x
) @trusted pure nothrow @nogc // TODO: @safe
972 version (InlineAsm_X87
)
974 import std
.math
.constants
: LOG2E
;
976 // e^^x = 2^^(LOG2E*x)
977 // (This is valid because the overflow & underflow limits for exp
978 // and exp2 are so similar).
980 return exp2Asm(LOG2E
*x
);
987 double exp(double x
) @safe pure nothrow @nogc { return __ctfe ?
cast(double) exp(cast(real) x
) : expImpl(x
); }
991 float exp(float x
) @safe pure nothrow @nogc { return __ctfe ?
cast(float) exp(cast(real) x
) : expImpl(x
); }
996 import std
.math
.operations
: feqrel
;
997 import std
.math
.constants
: E
;
999 assert(exp(0.0) == 1.0);
1000 assert(exp(3.0).feqrel(E
* E
* E
) > 16);
1003 private T
expImpl(T
)(T x
) @safe pure nothrow @nogc
1005 import std
.math
.traits
: floatTraits
, RealFormat
, isNaN
;
1006 import std
.math
.rounding
: floor
;
1007 import std
.math
.algebraic
: poly
;
1008 import std
.math
.constants
: LOG2E
;
1010 alias F
= floatTraits
!T
;
1011 static if (F
.realFormat
== RealFormat
.ieeeSingle
)
1013 static immutable T
[6] P
= [
1022 enum T C1
= 0.693359375;
1023 enum T C2
= -2.12194440e-4;
1025 // Overflow and Underflow limits.
1026 enum T OF
= 88.72283905206835;
1027 enum T UF
= -103.278929903431851103; // ln(2^-149)
1029 else static if (F
.realFormat
== RealFormat
.ieeeDouble
)
1031 // Coefficients for exp(x)
1032 static immutable T
[3] P
= [
1033 9.99999999999999999910E-1L,
1034 3.02994407707441961300E-2L,
1035 1.26177193074810590878E-4L,
1037 static immutable T
[4] Q
= [
1038 2.00000000000000000009E0L
,
1039 2.27265548208155028766E-1L,
1040 2.52448340349684104192E-3L,
1041 3.00198505138664455042E-6L,
1045 enum T C1
= 6.93145751953125E-1;
1046 enum T C2
= 1.42860682030941723212E-6;
1048 // Overflow and Underflow limits.
1049 enum T OF
= 7.09782712893383996732E2
; // ln((1-2^-53) * 2^1024)
1050 enum T UF
= -7.451332191019412076235E2
; // ln(2^-1075)
1052 else static if (F
.realFormat
== RealFormat
.ieeeExtended ||
1053 F
.realFormat
== RealFormat
.ieeeExtended53
)
1055 // Coefficients for exp(x)
1056 static immutable T
[3] P
= [
1057 9.9999999999999999991025E-1L,
1058 3.0299440770744196129956E-2L,
1059 1.2617719307481059087798E-4L,
1061 static immutable T
[4] Q
= [
1062 2.0000000000000000000897E0L
,
1063 2.2726554820815502876593E-1L,
1064 2.5244834034968410419224E-3L,
1065 3.0019850513866445504159E-6L,
1069 enum T C1
= 6.9314575195312500000000E-1L;
1070 enum T C2
= 1.4286068203094172321215E-6L;
1072 // Overflow and Underflow limits.
1073 enum T OF
= 1.1356523406294143949492E4L
; // ln((1-2^-64) * 2^16384)
1074 enum T UF
= -1.13994985314888605586758E4L
; // ln(2^-16446)
1076 else static if (F
.realFormat
== RealFormat
.ieeeQuadruple
)
1078 // Coefficients for exp(x) - 1
1079 static immutable T
[5] P
= [
1080 9.999999999999999999999999999999999998502E-1L,
1081 3.508710990737834361215404761139478627390E-2L,
1082 2.708775201978218837374512615596512792224E-4L,
1083 6.141506007208645008909088812338454698548E-7L,
1084 3.279723985560247033712687707263393506266E-10L
1086 static immutable T
[6] Q
= [
1087 2.000000000000000000000000000000000000150E0
,
1088 2.368408864814233538909747618894558968880E-1L,
1089 3.611828913847589925056132680618007270344E-3L,
1090 1.504792651814944826817779302637284053660E-5L,
1091 1.771372078166251484503904874657985291164E-8L,
1092 2.980756652081995192255342779918052538681E-12L
1096 enum T C1
= 6.93145751953125E-1L;
1097 enum T C2
= 1.428606820309417232121458176568075500134E-6L;
1099 // Overflow and Underflow limits.
1100 enum T OF
= 1.135583025911358400418251384584930671458833e4L
;
1101 enum T UF
= -1.143276959615573793352782661133116431383730e4L
;
1104 static assert(0, "Not implemented for this architecture");
1110 return real.infinity
;
1114 // Express: e^^x = e^^g * 2^^n
1115 // = e^^g * e^^(n * LOG2E)
1116 // = e^^(g + n * LOG2E)
1117 T xx
= floor((cast(T
) LOG2E
) * x
+ cast(T
) 0.5);
1118 const int n
= cast(int) xx
;
1122 static if (F
.realFormat
== RealFormat
.ieeeSingle
)
1125 x
= poly(x
, P
) * xx
+ x
+ 1.0f;
1129 // Rational approximation for exponential of the fractional part:
1130 // e^^x = 1 + 2x P(x^^2) / (Q(x^^2) - P(x^^2))
1132 const T px
= x
* poly(xx
, P
);
1133 x
= px
/ (poly(xx
, Q
) - px
);
1134 x
= (cast(T
) 1.0) + (cast(T
) 2.0) * x
;
1137 // Scale by power of 2.
1138 x
= core
.math
.ldexp(x
, n
);
1143 @safe @nogc nothrow unittest
1145 import std
.math
.traits
: floatTraits
, RealFormat
;
1146 import std
.math
.operations
: NaN
, feqrel
, isClose
;
1147 import std
.math
.constants
: E
;
1148 import std
.math
.traits
: isIdentical
;
1149 import std
.math
.algebraic
: abs
;
1151 version (IeeeFlagsSupport
) import std
.math
.hardware
: IeeeFlags
, resetIeeeFlags
, ieeeFlags
;
1152 version (FloatingPointControlSupport
)
1154 import std
.math
.hardware
: FloatingPointControl
;
1156 FloatingPointControl ctrl
;
1157 if (FloatingPointControl
.hasExceptionTraps
)
1158 ctrl
.disableExceptions(FloatingPointControl
.allExceptions
);
1159 ctrl
.rounding
= FloatingPointControl
.roundToNearest
;
1162 static void testExp(T
)()
1164 enum realFormat
= floatTraits
!T
.realFormat
;
1165 static if (realFormat
== RealFormat
.ieeeQuadruple
)
1167 static immutable T
[2][] exptestpoints
=
1170 [ 0.5L, 0x1.a61298e1e069bc972dfefab6df34p
+0L ],
1172 [ 0x1.6p
+13L, 0x1.6e509d45728655cdb4840542acb5p
+16250L ], // near overflow
1173 [ 0x1.7p
+13L, T
.infinity
], // close overflow
1174 [ 0x1p
+80L, T
.infinity
], // far overflow
1175 [ T
.infinity
, T
.infinity
],
1176 [-0x1.18p
+13L, 0x1.5e4bf54b4807034ea97fef0059a6p
-12927L ], // near underflow
1177 [-0x1.625p
+13L, 0x1.a6bd68a39d11fec3a250cd97f524p
-16358L ], // ditto
1178 [-0x1.62dafp
+13L, 0x0.cb629e9813b80ed4d639e875be6cp
-16382L ], // near underflow - subnormal
1179 [-0x1.6549p
+13L, 0x0.0000000000000000000000000001p
-16382L ], // ditto
1180 [-0x1.655p
+13L, 0 ], // close underflow
1181 [-0x1p
+30L, 0 ], // far underflow
1184 else static if (realFormat
== RealFormat
.ieeeExtended ||
1185 realFormat
== RealFormat
.ieeeExtended53
)
1187 static immutable T
[2][] exptestpoints
=
1190 [ 0.5L, 0x1.a61298e1e069bc97p
+0L ],
1192 [ 0x1.1p
+13L, 0x1.29aeffefc8ec645p
+12557L ], // near overflow
1193 [ 0x1.7p
+13L, T
.infinity
], // close overflow
1194 [ 0x1p
+80L, T
.infinity
], // far overflow
1195 [ T
.infinity
, T
.infinity
],
1196 [-0x1.18p
+13L, 0x1.5e4bf54b4806db9p
-12927L ], // near underflow
1197 [-0x1.625p
+13L, 0x1.a6bd68a39d11f35cp
-16358L ], // ditto
1198 [-0x1.62dafp
+13L, 0x1.96c53d30277021dp
-16383L ], // near underflow - subnormal
1199 [-0x1.643p
+13L, 0x1p
-16444L ], // ditto
1200 [-0x1.645p
+13L, 0 ], // close underflow
1201 [-0x1p
+30L, 0 ], // far underflow
1204 else static if (realFormat
== RealFormat
.ieeeDouble
)
1206 static immutable T
[2][] exptestpoints
=
1209 [ 0.5L, 0x1.a61298e1e069cp
+0L ],
1211 [ 0x1.6p
+9L, 0x1.93bf4ec
282efbp
+1015L ], // near overflow
1212 [ 0x1.7p
+9L, T
.infinity
], // close overflow
1213 [ 0x1p
+80L, T
.infinity
], // far overflow
1214 [ T
.infinity
, T
.infinity
],
1215 [-0x1.6p
+9L, 0x1.44a3824e5285fp
-1016L ], // near underflow
1216 [-0x1.64p
+9L, 0x0.06f84920bb2d4p
-1022L ], // near underflow - subnormal
1217 [-0x1.743p
+9L, 0x0.0000000000001p
-1022L ], // ditto
1218 [-0x1.8p
+9L, 0 ], // close underflow
1219 [-0x1p
+30L, 0 ], // far underflow
1222 else static if (realFormat
== RealFormat
.ieeeSingle
)
1224 static immutable T
[2][] exptestpoints
=
1227 [ 0.5L, 0x1.a61299p
+0L ],
1229 [ 0x1.62p
+6L, 0x1.99b988p
+127L ], // near overflow
1230 [ 0x1.7p
+6L, T
.infinity
], // close overflow
1231 [ 0x1p
+80L, T
.infinity
], // far overflow
1232 [ T
.infinity
, T
.infinity
],
1233 [-0x1.5cp
+6L, 0x1.666d0ep
-126L ], // near underflow
1234 [-0x1.7p
+6L, 0x0.026a42p
-126L ], // near underflow - subnormal
1235 [-0x1.9cp
+6L, 0x0.000002p
-126L ], // ditto
1236 [-0x1.ap
+6L, 0 ], // close underflow
1237 [-0x1p
+30L, 0 ], // far underflow
1241 static assert(0, "No exp() tests for real type!");
1243 const minEqualMantissaBits
= T
.mant_dig
- 13;
1245 version (IeeeFlagsSupport
) IeeeFlags f
;
1246 foreach (ref pair
; exptestpoints
)
1248 version (IeeeFlagsSupport
) resetIeeeFlags();
1250 //printf("exp(%La) = %La, should be %La\n", cast(real) pair[0], cast(real) x, cast(real) pair[1]);
1251 assert(feqrel(x
, pair
[1]) >= minEqualMantissaBits
);
1254 // Ideally, exp(0) would not set the inexact flag.
1255 // Unfortunately, fldl2e sets it!
1256 // So it's not realistic to avoid setting it.
1257 assert(exp(cast(T
) 0.0) == 1.0);
1259 // NaN propagation. Doesn't set flags, bcos was already NaN.
1260 version (IeeeFlagsSupport
)
1265 assert(isIdentical(abs(x
), T
.nan
));
1266 assert(f
.flags
== 0);
1271 assert(isIdentical(abs(x
), T
.nan
));
1272 assert(f
.flags
== 0);
1277 assert(isIdentical(abs(x
), T
.nan
));
1280 assert(isIdentical(abs(x
), T
.nan
));
1283 x
= exp(NaN(0x123));
1284 assert(isIdentical(x
, NaN(0x123)));
1287 import std
.meta
: AliasSeq
;
1288 foreach (T
; AliasSeq
!(real, double, float))
1291 // High resolution test (verified against GNU MPFR/Mathematica).
1292 assert(exp(0.5L) == 0x1.A612_98E1_E069_BC97_2DFE_FAB6_DF34p
+0L);
1294 assert(isClose(exp(3.0L), E
* E
* E
, real.sizeof
> double.sizeof ?
1e-15 : 1e-14));
1298 * Calculates the value of the natural logarithm base (e)
1299 * raised to the power of x, minus 1.
1301 * For very small x, expm1(x) is more accurate
1305 * $(TR $(TH x) $(TH e$(SUPERSCRIPT x)-1) )
1306 * $(TR $(TD $(PLUSMN)0.0) $(TD $(PLUSMN)0.0) )
1307 * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) )
1308 * $(TR $(TD -$(INFIN)) $(TD -1.0) )
1309 * $(TR $(TD $(NAN)) $(TD $(NAN)) )
1312 pragma(inline
, true)
1313 real expm1(real x
) @trusted pure nothrow @nogc // TODO: @safe
1315 version (InlineAsm_X87
)
1320 return expm1Impl(x
);
1324 pragma(inline
, true)
1325 double expm1(double x
) @safe pure nothrow @nogc
1327 return __ctfe ?
cast(double) expm1(cast(real) x
) : expm1Impl(x
);
1331 pragma(inline
, true)
1332 float expm1(float x
) @safe pure nothrow @nogc
1334 // no single-precision version in Cephes => use double precision
1335 return __ctfe ?
cast(float) expm1(cast(real) x
) : cast(float) expm1Impl(cast(double) x
);
1341 import std
.math
.traits
: isIdentical
;
1342 import std
.math
.operations
: feqrel
;
1344 assert(isIdentical(expm1(0.0), 0.0));
1345 assert(expm1(1.0).feqrel(1.71828) > 16);
1346 assert(expm1(2.0).feqrel(6.3890) > 16);
1349 version (InlineAsm_X87
)
1350 private real expm1Asm(real x
) @trusted pure nothrow @nogc
1354 enum PARAMSIZE
= (real.sizeof
+3)&(0xFFFF_FFFC
); // always a multiple of 4
1355 asm pure nothrow @nogc
1357 /* expm1() for x87 80-bit reals, IEEE754-2008 conformant.
1358 * Author: Don Clugston.
1360 * expm1(x) = 2^^(rndint(y))* 2^^(y-rndint(y)) - 1 where y = LN2*x.
1361 * = 2rndy * 2ym1 + 2rndy - 1, where 2rndy = 2^^(rndint(y))
1362 * and 2ym1 = (2^^(y-rndint(y))-1).
1363 * If 2rndy < 0.5*real.epsilon, result is -1.
1364 * Implementation is otherwise the same as for exp2()
1367 fld real ptr
[ESP
+4] ; // x
1368 mov AX
, [ESP
+4+8]; // AX = exponent and sign
1369 sub ESP
, 12+8; // Create scratch space on the stack
1370 // [ESP,ESP+2] = scratchint
1371 // [ESP+4..+6, +8..+10, +10] = scratchreal
1372 // set scratchreal mantissa = 1.0
1373 mov dword ptr
[ESP
+8], 0;
1374 mov dword ptr
[ESP
+8+4], 0x80000000;
1375 and AX
, 0x7FFF; // drop sign bit
1376 cmp AX
, 0x401D; // avoid InvalidException in fist
1379 fmulp ST(1), ST
; // y = x*log2(e)
1380 fist dword ptr
[ESP
]; // scratchint = rndint(y)
1381 fisub dword ptr
[ESP
]; // y - rndint(y)
1382 // and now set scratchreal exponent
1385 jle short L_largenegative
;
1387 jge short L_largepositive
;
1389 f2xm1; // 2ym1 = 2^^(y-rndint(y)) -1
1390 fld real ptr
[ESP
+8] ; // 2rndy = 2^^rndint(y)
1391 fmul ST(1), ST
; // ST=2rndy, ST(1)=2rndy*2ym1
1393 fsubp ST(1), ST
; // ST = 2rndy-1, ST(1) = 2rndy * 2ym1 - 1
1394 faddp ST(1), ST
; // ST = 2rndy * 2ym1 + 2rndy - 1
1398 L_extreme
: // Extreme exponent. X is very large positive, very
1399 // large negative, infinity, or NaN.
1402 test AX
, 0x0400; // NaN_or_zero, but we already know x != 0
1403 jz L_was_nan
; // if x is NaN, returns x
1405 jnz L_largenegative
;
1407 // Set scratchreal = real.max.
1408 // squaring it will create infinity, and set overflow flag.
1409 mov word ptr
[ESP
+8+8], 0x7FFE;
1411 fld real ptr
[ESP
+8]; // load scratchreal
1412 fmul ST(0), ST
; // square it, to create havoc!
1419 fchs; // return -1. Underflow flag is not set.
1424 else version (X86_64
)
1426 asm pure nothrow @nogc
1432 asm pure nothrow @nogc
1434 fld real ptr
[RCX
]; // x
1435 mov AX
,[RCX
+8]; // AX = exponent and sign
1440 asm pure nothrow @nogc
1442 fld real ptr
[RSP
+8]; // x
1443 mov AX
,[RSP
+8+8]; // AX = exponent and sign
1446 asm pure nothrow @nogc
1448 /* expm1() for x87 80-bit reals, IEEE754-2008 conformant.
1449 * Author: Don Clugston.
1451 * expm1(x) = 2^(rndint(y))* 2^(y-rndint(y)) - 1 where y = LN2*x.
1452 * = 2rndy * 2ym1 + 2rndy - 1, where 2rndy = 2^(rndint(y))
1453 * and 2ym1 = (2^(y-rndint(y))-1).
1454 * If 2rndy < 0.5*real.epsilon, result is -1.
1455 * Implementation is otherwise the same as for exp2()
1457 sub RSP
, 24; // Create scratch space on the stack
1458 // [RSP,RSP+2] = scratchint
1459 // [RSP+4..+6, +8..+10, +10] = scratchreal
1460 // set scratchreal mantissa = 1.0
1461 mov dword ptr
[RSP
+8], 0;
1462 mov dword ptr
[RSP
+8+4], 0x80000000;
1463 and AX
, 0x7FFF; // drop sign bit
1464 cmp AX
, 0x401D; // avoid InvalidException in fist
1467 fmul ; // y = x*log2(e)
1468 fist dword ptr
[RSP
]; // scratchint = rndint(y)
1469 fisub dword ptr
[RSP
]; // y - rndint(y)
1470 // and now set scratchreal exponent
1473 jle short L_largenegative
;
1475 jge short L_largepositive
;
1477 f2xm1; // 2^(y-rndint(y)) -1
1478 fld real ptr
[RSP
+8] ; // 2^rndint(y)
1486 L_extreme
: // Extreme exponent. X is very large positive, very
1487 // large negative, infinity, or NaN.
1490 test AX
, 0x0400; // NaN_or_zero, but we already know x != 0
1491 jz L_was_nan
; // if x is NaN, returns x
1493 jnz L_largenegative
;
1495 // Set scratchreal = real.max.
1496 // squaring it will create infinity, and set overflow flag.
1497 mov word ptr
[RSP
+8+8], 0x7FFE;
1499 fld real ptr
[RSP
+8]; // load scratchreal
1500 fmul ST(0), ST
; // square it, to create havoc!
1508 fchs; // return -1. Underflow flag is not set.
1517 private T
expm1Impl(T
)(T x
) @safe pure nothrow @nogc
1519 import std
.math
.traits
: floatTraits
, RealFormat
;
1520 import std
.math
.rounding
: floor
;
1521 import std
.math
.algebraic
: poly
;
1522 import std
.math
.constants
: LN2
;
1524 // Coefficients for exp(x) - 1 and overflow/underflow limits.
1525 enum realFormat
= floatTraits
!T
.realFormat
;
1526 static if (realFormat
== RealFormat
.ieeeQuadruple
)
1528 static immutable T
[8] P
= [
1529 2.943520915569954073888921213330863757240E8L
,
1530 -5.722847283900608941516165725053359168840E7L
,
1531 8.944630806357575461578107295909719817253E6L
,
1532 -7.212432713558031519943281748462837065308E5L
,
1533 4.578962475841642634225390068461943438441E4L
,
1534 -1.716772506388927649032068540558788106762E3L
,
1535 4.401308817383362136048032038528753151144E1L
,
1536 -4.888737542888633647784737721812546636240E-1L
1539 static immutable T
[9] Q
= [
1540 1.766112549341972444333352727998584753865E9L
,
1541 -7.848989743695296475743081255027098295771E8L
,
1542 1.615869009634292424463780387327037251069E8L
,
1543 -2.019684072836541751428967854947019415698E7L
,
1544 1.682912729190313538934190635536631941751E6L
,
1545 -9.615511549171441430850103489315371768998E4L
,
1546 3.697714952261803935521187272204485251835E3L
,
1547 -8.802340681794263968892934703309274564037E1L
,
1551 enum T OF
= 1.1356523406294143949491931077970764891253E4L
;
1552 enum T UF
= -1.143276959615573793352782661133116431383730e4L
;
1554 else static if (realFormat
== RealFormat
.ieeeExtended
)
1556 static immutable T
[5] P
= [
1557 -1.586135578666346600772998894928250240826E4L
,
1558 2.642771505685952966904660652518429479531E3L
,
1559 -3.423199068835684263987132888286791620673E2L
,
1560 1.800826371455042224581246202420972737840E1L
,
1561 -5.238523121205561042771939008061958820811E-1L,
1563 static immutable T
[6] Q
= [
1564 -9.516813471998079611319047060563358064497E4L
,
1565 3.964866271411091674556850458227710004570E4L
,
1566 -7.207678383830091850230366618190187434796E3L
,
1567 7.206038318724600171970199625081491823079E2L
,
1568 -4.002027679107076077238836622982900945173E1L
,
1572 enum T OF
= 1.1356523406294143949492E4L
;
1573 enum T UF
= -4.5054566736396445112120088E1L
;
1575 else static if (realFormat
== RealFormat
.ieeeDouble
)
1577 static immutable T
[3] P
= [
1578 9.9999999999999999991025E-1,
1579 3.0299440770744196129956E-2,
1580 1.2617719307481059087798E-4,
1582 static immutable T
[4] Q
= [
1583 2.0000000000000000000897E0
,
1584 2.2726554820815502876593E-1,
1585 2.5244834034968410419224E-3,
1586 3.0019850513866445504159E-6,
1590 static assert(0, "no coefficients for expm1()");
1592 static if (realFormat
== RealFormat
.ieeeDouble
) // special case for double precision
1594 if (x
< -0.5 || x
> 0.5)
1595 return exp(x
) - 1.0;
1600 x
= x
* poly(xx
, P
);
1601 x
= x
/ (poly(xx
, Q
) - x
);
1607 enum T C1
= 6.9314575195312500000000E-1L;
1608 enum T C2
= 1.428606820309417232121458176568075500134E-6L;
1612 return real.infinity
;
1613 if (x
== cast(T
) 0.0)
1618 // Express x = LN2 (n + remainder), remainder not exceeding 1/2.
1619 int n
= cast(int) floor((cast(T
) 0.5) + x
/ cast(T
) LN2
);
1623 // Rational approximation:
1624 // exp(x) - 1 = x + 0.5 x^^2 + x^^3 P(x) / Q(x)
1625 T px
= x
* poly(x
, P
);
1628 qx
= x
+ ((cast(T
) 0.5) * xx
+ xx
* px
/ qx
);
1630 // We have qx = exp(remainder LN2) - 1, so:
1631 // exp(x) - 1 = 2^^n (qx + 1) - 1 = 2^^n qx + 2^^n - 1.
1632 px
= core
.math
.ldexp(cast(T
) 1.0, n
);
1633 x
= px
* qx
+ (px
- cast(T
) 1.0);
1639 @safe @nogc nothrow unittest
1641 import std
.math
.traits
: isNaN
;
1642 import std
.math
.operations
: isClose
, CommonDefaultFor
;
1644 static void testExpm1(T
)()
1647 assert(isNaN(expm1(cast(T
) T
.nan
)));
1649 static immutable T
[] xs
= [ -2, -0.75, -0.3, 0.0, 0.1, 0.2, 0.5, 1.0 ];
1652 const T e
= expm1(x
);
1653 const T r
= exp(x
) - 1;
1655 //printf("expm1(%Lg) = %Lg, should approximately be %Lg\n", cast(real) x, cast(real) e, cast(real) r);
1656 assert(isClose(r
, e
, CommonDefaultFor
!(T
,T
), CommonDefaultFor
!(T
,T
)));
1660 import std
.meta
: AliasSeq
;
1661 foreach (T
; AliasSeq
!(real, double))
1666 * Calculates 2$(SUPERSCRIPT x).
1669 * $(TR $(TH x) $(TH exp2(x)) )
1670 * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) )
1671 * $(TR $(TD -$(INFIN)) $(TD +0.0) )
1672 * $(TR $(TD $(NAN)) $(TD $(NAN)) )
1675 pragma(inline
, true)
1676 real exp2(real x
) @nogc @trusted pure nothrow // TODO: @safe
1678 version (InlineAsm_X87
)
1687 pragma(inline
, true)
1688 double exp2(double x
) @nogc @safe pure nothrow { return __ctfe ?
cast(double) exp2(cast(real) x
) : exp2Impl(x
); }
1691 pragma(inline
, true)
1692 float exp2(float x
) @nogc @safe pure nothrow { return __ctfe ?
cast(float) exp2(cast(real) x
) : exp2Impl(x
); }
1697 import std
.math
.traits
: isIdentical
;
1698 import std
.math
.operations
: feqrel
;
1700 assert(isIdentical(exp2(0.0), 1.0));
1701 assert(exp2(2.0).feqrel(4.0) > 16);
1702 assert(exp2(8.0).feqrel(256.0) > 16);
1707 version (CRuntime_Microsoft
) {} else // aexp2/exp2f/exp2l not implemented
1709 assert( core
.stdc
.math
.exp2f(0.0f) == 1 );
1710 assert( core
.stdc
.math
.exp2 (0.0) == 1 );
1711 assert( core
.stdc
.math
.exp2l(0.0L) == 1 );
1715 version (InlineAsm_X87
)
1716 private real exp2Asm(real x
) @nogc @trusted pure nothrow
1720 enum PARAMSIZE
= (real.sizeof
+3)&(0xFFFF_FFFC
); // always a multiple of 4
1722 asm pure nothrow @nogc
1724 /* exp2() for x87 80-bit reals, IEEE754-2008 conformant.
1725 * Author: Don Clugston.
1727 * exp2(x) = 2^^(rndint(x))* 2^^(y-rndint(x))
1728 * The trick for high performance is to avoid the fscale(28cycles on core2),
1729 * frndint(19 cycles), leaving f2xm1(19 cycles) as the only slow instruction.
1731 * We can do frndint by using fist. BUT we can't use it for huge numbers,
1732 * because it will set the Invalid Operation flag if overflow or NaN occurs.
1733 * Fortunately, whenever this happens the result would be zero or infinity.
1735 * We can perform fscale by directly poking into the exponent. BUT this doesn't
1736 * work for the (very rare) cases where the result is subnormal. So we fall back
1737 * to the slow method in that case.
1740 fld real ptr
[ESP
+4] ; // x
1741 mov AX
, [ESP
+4+8]; // AX = exponent and sign
1742 sub ESP
, 12+8; // Create scratch space on the stack
1743 // [ESP,ESP+2] = scratchint
1744 // [ESP+4..+6, +8..+10, +10] = scratchreal
1745 // set scratchreal mantissa = 1.0
1746 mov dword ptr
[ESP
+8], 0;
1747 mov dword ptr
[ESP
+8+4], 0x80000000;
1748 and AX
, 0x7FFF; // drop sign bit
1749 cmp AX
, 0x401D; // avoid InvalidException in fist
1751 fist dword ptr
[ESP
]; // scratchint = rndint(x)
1752 fisub dword ptr
[ESP
]; // x - rndint(x)
1753 // and now set scratchreal exponent
1756 jle short L_subnormal
;
1758 jge short L_overflow
;
1763 faddp ST(1), ST
; // 2^^(x-rndint(x))
1764 fld real ptr
[ESP
+8] ; // 2^^rndint(x)
1770 // Result will be subnormal.
1771 // In this rare case, the simple poking method doesn't work.
1772 // The speed doesn't matter, so use the slow fscale method.
1773 fild dword ptr
[ESP
]; // scratchint
1776 fstp real ptr
[ESP
+8]; // scratchreal = 2^^scratchint
1777 fstp ST(0); // drop scratchint
1780 L_extreme
: // Extreme exponent. X is very large positive, very
1781 // large negative, infinity, or NaN.
1784 test AX
, 0x0400; // NaN_or_zero, but we already know x != 0
1785 jz L_was_nan
; // if x is NaN, returns x
1786 // set scratchreal = real.min_normal
1787 // squaring it will return 0, setting underflow flag
1788 mov word ptr
[ESP
+8+8], 1;
1790 jnz L_waslargenegative
;
1792 // Set scratchreal = real.max.
1793 // squaring it will create infinity, and set overflow flag.
1794 mov word ptr
[ESP
+8+8], 0x7FFE;
1797 fld real ptr
[ESP
+8]; // load scratchreal
1798 fmul ST(0), ST
; // square it, to create havoc!
1804 else version (X86_64
)
1806 asm pure nothrow @nogc
1812 asm pure nothrow @nogc
1814 fld real ptr
[RCX
]; // x
1815 mov AX
,[RCX
+8]; // AX = exponent and sign
1820 asm pure nothrow @nogc
1822 fld real ptr
[RSP
+8]; // x
1823 mov AX
,[RSP
+8+8]; // AX = exponent and sign
1826 asm pure nothrow @nogc
1828 /* exp2() for x87 80-bit reals, IEEE754-2008 conformant.
1829 * Author: Don Clugston.
1831 * exp2(x) = 2^(rndint(x))* 2^(y-rndint(x))
1832 * The trick for high performance is to avoid the fscale(28cycles on core2),
1833 * frndint(19 cycles), leaving f2xm1(19 cycles) as the only slow instruction.
1835 * We can do frndint by using fist. BUT we can't use it for huge numbers,
1836 * because it will set the Invalid Operation flag is overflow or NaN occurs.
1837 * Fortunately, whenever this happens the result would be zero or infinity.
1839 * We can perform fscale by directly poking into the exponent. BUT this doesn't
1840 * work for the (very rare) cases where the result is subnormal. So we fall back
1841 * to the slow method in that case.
1843 sub RSP
, 24; // Create scratch space on the stack
1844 // [RSP,RSP+2] = scratchint
1845 // [RSP+4..+6, +8..+10, +10] = scratchreal
1846 // set scratchreal mantissa = 1.0
1847 mov dword ptr
[RSP
+8], 0;
1848 mov dword ptr
[RSP
+8+4], 0x80000000;
1849 and AX
, 0x7FFF; // drop sign bit
1850 cmp AX
, 0x401D; // avoid InvalidException in fist
1852 fist dword ptr
[RSP
]; // scratchint = rndint(x)
1853 fisub dword ptr
[RSP
]; // x - rndint(x)
1854 // and now set scratchreal exponent
1857 jle short L_subnormal
;
1859 jge short L_overflow
;
1864 fadd; // 2^(x-rndint(x))
1865 fld real ptr
[RSP
+8] ; // 2^rndint(x)
1871 // Result will be subnormal.
1872 // In this rare case, the simple poking method doesn't work.
1873 // The speed doesn't matter, so use the slow fscale method.
1874 fild dword ptr
[RSP
]; // scratchint
1877 fstp real ptr
[RSP
+8]; // scratchreal = 2^scratchint
1878 fstp ST(0); // drop scratchint
1881 L_extreme
: // Extreme exponent. X is very large positive, very
1882 // large negative, infinity, or NaN.
1885 test AX
, 0x0400; // NaN_or_zero, but we already know x != 0
1886 jz L_was_nan
; // if x is NaN, returns x
1887 // set scratchreal = real.min
1888 // squaring it will return 0, setting underflow flag
1889 mov word ptr
[RSP
+8+8], 1;
1891 jnz L_waslargenegative
;
1893 // Set scratchreal = real.max.
1894 // squaring it will create infinity, and set overflow flag.
1895 mov word ptr
[RSP
+8+8], 0x7FFE;
1898 fld real ptr
[RSP
+8]; // load scratchreal
1899 fmul ST(0), ST
; // square it, to create havoc!
1909 private T
exp2Impl(T
)(T x
) @nogc @safe pure nothrow
1911 import std
.math
.traits
: floatTraits
, RealFormat
, isNaN
;
1912 import std
.math
.rounding
: floor
;
1913 import std
.math
.algebraic
: poly
;
1915 // Coefficients for exp2(x)
1916 enum realFormat
= floatTraits
!T
.realFormat
;
1917 static if (realFormat
== RealFormat
.ieeeQuadruple
)
1919 static immutable T
[5] P
= [
1920 9.079594442980146270952372234833529694788E12L
,
1921 1.530625323728429161131811299626419117557E11L
,
1922 5.677513871931844661829755443994214173883E8L
,
1923 6.185032670011643762127954396427045467506E5L
,
1924 1.587171580015525194694938306936721666031E2L
1927 static immutable T
[6] Q
= [
1928 2.619817175234089411411070339065679229869E13L
,
1929 1.490560994263653042761789432690793026977E12L
,
1930 1.092141473886177435056423606755843616331E10L
,
1931 2.186249607051644894762167991800811827835E7L
,
1932 1.236602014442099053716561665053645270207E4L
,
1936 else static if (realFormat
== RealFormat
.ieeeExtended
)
1938 static immutable T
[3] P
= [
1939 2.0803843631901852422887E6L
,
1940 3.0286971917562792508623E4L
,
1941 6.0614853552242266094567E1L
,
1943 static immutable T
[4] Q
= [
1944 6.0027204078348487957118E6L
,
1945 3.2772515434906797273099E5L
,
1946 1.7492876999891839021063E3L
,
1947 1.0000000000000000000000E0L
,
1950 else static if (realFormat
== RealFormat
.ieeeDouble
)
1952 static immutable T
[3] P
= [
1953 1.51390680115615096133E3L
,
1954 2.02020656693165307700E1L
,
1955 2.30933477057345225087E-2L,
1957 static immutable T
[3] Q
= [
1958 4.36821166879210612817E3L
,
1959 2.33184211722314911771E2L
,
1960 1.00000000000000000000E0L
,
1963 else static if (realFormat
== RealFormat
.ieeeSingle
)
1965 static immutable T
[6] P
= [
1966 6.931472028550421E-001L,
1967 2.402264791363012E-001L,
1968 5.550332471162809E-002L,
1969 9.618437357674640E-003L,
1970 1.339887440266574E-003L,
1971 1.535336188319500E-004L,
1975 static assert(0, "no coefficients for exp2()");
1977 // Overflow and Underflow limits.
1978 enum T OF
= T
.max_exp
;
1979 enum T UF
= T
.min_exp
- 1;
1985 return real.infinity
;
1989 static if (realFormat
== RealFormat
.ieeeSingle
) // special case for single precision
1991 // The following is necessary because range reduction blows up.
1995 // Separate into integer and fractional parts.
1996 const T i
= floor(x
);
1997 int n
= cast(int) i
;
2005 // Rational approximation:
2006 // exp2(x) = 1.0 + x P(x)
2007 x
= 1.0f + x
* poly(x
, P
);
2011 // Separate into integer and fractional parts.
2012 const T i
= floor(x
+ cast(T
) 0.5);
2013 int n
= cast(int) i
;
2016 // Rational approximation:
2017 // exp2(x) = 1.0 + 2x P(x^^2) / (Q(x^^2) - P(x^^2))
2019 const T px
= x
* poly(xx
, P
);
2020 x
= px
/ (poly(xx
, Q
) - px
);
2021 x
= (cast(T
) 1.0) + (cast(T
) 2.0) * x
;
2024 // Scale by power of 2.
2025 x
= core
.math
.ldexp(x
, n
);
2030 @safe @nogc nothrow unittest
2032 import std
.math
.operations
: feqrel
, NaN
, isClose
;
2033 import std
.math
.traits
: isIdentical
;
2034 import std
.math
.constants
: SQRT2
;
2036 assert(feqrel(exp2(0.5L), SQRT2
) >= real.mant_dig
-1);
2037 assert(exp2(8.0L) == 256.0);
2038 assert(exp2(-9.0L)== 1.0L/512.0);
2040 static void testExp2(T
)()
2043 const T specialNaN
= NaN(0x0123L
);
2044 assert(isIdentical(exp2(specialNaN
), specialNaN
));
2047 enum T OF
= T
.max_exp
;
2048 enum T UF
= T
.min_exp
- T
.mant_dig
;
2049 assert(isIdentical(exp2(OF
+ 1), cast(T
) T
.infinity
));
2050 assert(isIdentical(exp2(UF
- 1), cast(T
) 0.0));
2052 static immutable T
[2][] vals
=
2059 [ -9.0, 1.0 / 512 ],
2062 foreach (ref val
; vals
)
2066 const T e
= exp2(x
);
2068 //printf("exp2(%Lg) = %Lg, should be %Lg\n", cast(real) x, cast(real) e, cast(real) r);
2069 assert(isClose(r
, e
));
2073 import std
.meta
: AliasSeq
;
2074 foreach (T
; AliasSeq
!(real, double, float))
2078 /*********************************************************************
2079 * Separate floating point value into significand and exponent.
2082 * Calculate and return $(I x) and $(I exp) such that
2083 * value =$(I x)*2$(SUPERSCRIPT exp) and
2084 * .5 $(LT)= |$(I x)| $(LT) 1.0
2086 * $(I x) has same sign as value.
2089 * $(TR $(TH value) $(TH returns) $(TH exp))
2090 * $(TR $(TD $(PLUSMN)0.0) $(TD $(PLUSMN)0.0) $(TD 0))
2091 * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) $(TD int.max))
2092 * $(TR $(TD -$(INFIN)) $(TD -$(INFIN)) $(TD int.min))
2093 * $(TR $(TD $(PLUSMN)$(NAN)) $(TD $(PLUSMN)$(NAN)) $(TD int.min))
2096 T
frexp(T
)(const T value
, out int exp
) @trusted pure nothrow @nogc
2097 if (isFloatingPoint
!T
)
2099 import std
.math
.traits
: floatTraits
, RealFormat
, MANTISSA_MSB
, MANTISSA_LSB
, isSubnormal
;
2103 // Handle special cases.
2104 if (value
== 0) { exp
= 0; return value
; }
2105 if (value
== T
.infinity
) { exp
= int.max
; return value
; }
2106 if (value
== -T
.infinity || value
!= value
) { exp
= int.min
; return value
; }
2107 // Handle ordinary cases.
2108 // In CTFE there is no performance advantage for having separate
2109 // paths for different floating point types.
2110 T absValue
= value
< 0 ?
-value
: value
;
2112 static if (T
.mant_dig
> double.mant_dig
)
2114 for (; absValue
>= 0x1.0p
+1024L; absValue
*= 0x1.0p
-1024L)
2116 for (; absValue
< 0x1.0p
-1021L; absValue
*= 0x1.0p
+1021L)
2119 const double dval
= cast(double) absValue
;
2120 int dexp
= cast(int) (((*cast(const long*) &dval
) >>> 52) & 0x7FF) + double.min_exp
- 2;
2123 absValue
*= 2.0 ^^
-dexp
;
2124 // If the original value was subnormal or if it was a real
2125 // then absValue can still be outside the [0.5, 1.0) range.
2128 assert(T
.mant_dig
> double.mant_dig ||
isSubnormal(value
));
2131 absValue
+= absValue
;
2133 } while (absValue
< 0.5);
2137 assert(absValue
< 1 || T
.mant_dig
> double.mant_dig
);
2138 for (; absValue
>= 1; absValue
*= T(0.5))
2142 return value
< 0 ?
-absValue
: absValue
;
2145 Unqual
!T vf
= value
;
2146 ushort* vu
= cast(ushort*)&vf
;
2147 static if (is(immutable T
== immutable float))
2148 int* vi
= cast(int*)&vf
;
2150 long* vl
= cast(long*)&vf
;
2152 alias F
= floatTraits
!T
;
2154 ex
= vu
[F
.EXPPOS_SHORT
] & F
.EXPMASK
;
2155 static if (F
.realFormat
== RealFormat
.ieeeExtended ||
2156 F
.realFormat
== RealFormat
.ieeeExtended53
)
2159 { // If exponent is non-zero
2160 if (ex
== F
.EXPMASK
) // infinity or NaN
2162 if (*vl
& 0x7FFF_FFFF_FFFF_FFFF
) // NaN
2164 *vl |
= 0xC000_0000_0000_0000; // convert NaNS to NaNQ
2167 else if (vu
[F
.EXPPOS_SHORT
] & 0x8000) // negative infinity
2169 else // positive infinity
2175 exp
= ex
- F
.EXPBIAS
;
2176 vu
[F
.EXPPOS_SHORT
] = (0x8000 & vu
[F
.EXPPOS_SHORT
]) |
0x3FFE;
2188 vf
*= F
.RECIP_EPSILON
;
2189 ex
= vu
[F
.EXPPOS_SHORT
] & F
.EXPMASK
;
2190 exp
= ex
- F
.EXPBIAS
- T
.mant_dig
+ 1;
2191 vu
[F
.EXPPOS_SHORT
] = ((-1 - F
.EXPMASK
) & vu
[F
.EXPPOS_SHORT
]) |
0x3FFE;
2195 else static if (F
.realFormat
== RealFormat
.ieeeQuadruple
)
2197 if (ex
) // If exponent is non-zero
2199 if (ex
== F
.EXPMASK
)
2202 if (vl
[MANTISSA_LSB
] |
2203 (vl
[MANTISSA_MSB
] & 0x0000_FFFF_FFFF_FFFF
)) // NaN
2205 // convert NaNS to NaNQ
2206 vl
[MANTISSA_MSB
] |
= 0x0000_8000_0000_0000;
2209 else if (vu
[F
.EXPPOS_SHORT
] & 0x8000) // negative infinity
2211 else // positive infinity
2216 exp
= ex
- F
.EXPBIAS
;
2217 vu
[F
.EXPPOS_SHORT
] = F
.EXPBIAS |
(0x8000 & vu
[F
.EXPPOS_SHORT
]);
2220 else if ((vl
[MANTISSA_LSB
] |
2221 (vl
[MANTISSA_MSB
] & 0x0000_FFFF_FFFF_FFFF
)) == 0)
2229 vf
*= F
.RECIP_EPSILON
;
2230 ex
= vu
[F
.EXPPOS_SHORT
] & F
.EXPMASK
;
2231 exp
= ex
- F
.EXPBIAS
- T
.mant_dig
+ 1;
2232 vu
[F
.EXPPOS_SHORT
] = F
.EXPBIAS |
(0x8000 & vu
[F
.EXPPOS_SHORT
]);
2236 else static if (F
.realFormat
== RealFormat
.ieeeDouble
)
2238 if (ex
) // If exponent is non-zero
2240 if (ex
== F
.EXPMASK
) // infinity or NaN
2242 if (*vl
== 0x7FF0_0000_0000_0000) // positive infinity
2246 else if (*vl
== 0xFFF0_0000_0000_0000) // negative infinity
2250 *vl |
= 0x0008_0000_0000_0000; // convert NaNS to NaNQ
2256 exp
= (ex
- F
.EXPBIAS
) >> 4;
2257 vu
[F
.EXPPOS_SHORT
] = cast(ushort)((0x800F & vu
[F
.EXPPOS_SHORT
]) |
0x3FE0);
2260 else if (!(*vl
& 0x7FFF_FFFF_FFFF_FFFF
))
2268 vf
*= F
.RECIP_EPSILON
;
2269 ex
= vu
[F
.EXPPOS_SHORT
] & F
.EXPMASK
;
2270 exp
= ((ex
- F
.EXPBIAS
) >> 4) - T
.mant_dig
+ 1;
2271 vu
[F
.EXPPOS_SHORT
] =
2272 cast(ushort)(((-1 - F
.EXPMASK
) & vu
[F
.EXPPOS_SHORT
]) |
0x3FE0);
2276 else static if (F
.realFormat
== RealFormat
.ieeeSingle
)
2278 if (ex
) // If exponent is non-zero
2280 if (ex
== F
.EXPMASK
) // infinity or NaN
2282 if (*vi
== 0x7F80_0000) // positive infinity
2286 else if (*vi
== 0xFF80_0000) // negative infinity
2290 *vi |
= 0x0040_0000; // convert NaNS to NaNQ
2296 exp
= (ex
- F
.EXPBIAS
) >> 7;
2297 vu
[F
.EXPPOS_SHORT
] = cast(ushort)((0x807F & vu
[F
.EXPPOS_SHORT
]) |
0x3F00);
2300 else if (!(*vi
& 0x7FFF_FFFF
))
2308 vf
*= F
.RECIP_EPSILON
;
2309 ex
= vu
[F
.EXPPOS_SHORT
] & F
.EXPMASK
;
2310 exp
= ((ex
- F
.EXPBIAS
) >> 7) - T
.mant_dig
+ 1;
2311 vu
[F
.EXPPOS_SHORT
] =
2312 cast(ushort)(((-1 - F
.EXPMASK
) & vu
[F
.EXPPOS_SHORT
]) |
0x3F00);
2316 else // static if (F.realFormat == RealFormat.ibmExtended)
2318 assert(0, "frexp not implemented");
2325 import std
.math
.operations
: isClose
;
2328 real mantissa
= frexp(123.456L, exp
);
2330 assert(isClose(mantissa
* pow(2.0L, cast(real) exp
), 123.456L));
2332 assert(frexp(-real.nan
, exp
) && exp
== int.min
);
2333 assert(frexp(real.nan
, exp
) && exp
== int.min
);
2334 assert(frexp(-real.infinity
, exp
) == -real.infinity
&& exp
== int.min
);
2335 assert(frexp(real.infinity
, exp
) == real.infinity
&& exp
== int.max
);
2336 assert(frexp(-0.0, exp
) == -0.0 && exp
== 0);
2337 assert(frexp(0.0, exp
) == 0.0 && exp
== 0);
2340 @safe @nogc nothrow unittest
2342 import std
.math
.operations
: isClose
;
2345 real mantissa
= frexp(123.456L, exp
);
2347 // check if values are equal to 19 decimal digits of precision
2348 assert(isClose(mantissa
* pow(2.0L, cast(real) exp
), 123.456L, 1e-18));
2353 import std
.math
.traits
: floatTraits
, RealFormat
, isIdentical
;
2354 import std
.meta
: AliasSeq
;
2355 import std
.typecons
: tuple
, Tuple
;
2357 static foreach (T
; AliasSeq
!(real, double, float))
2359 Tuple
!(T
, T
, int)[] vals
= [ // x,frexp,exp
2360 tuple(T(0.0), T( 0.0 ), 0),
2361 tuple(T(-0.0), T( -0.0), 0),
2362 tuple(T(1.0), T( .5 ), 1),
2363 tuple(T(-1.0), T( -.5 ), 1),
2364 tuple(T(2.0), T( .5 ), 2),
2365 tuple(T(float.min_normal
/2.0f), T(.5), -126),
2366 tuple(T
.infinity
, T
.infinity
, int.max
),
2367 tuple(-T
.infinity
, -T
.infinity
, int.min
),
2368 tuple(T
.nan
, T
.nan
, int.min
),
2369 tuple(-T
.nan
, -T
.nan
, int.min
),
2371 // https://issues.dlang.org/show_bug.cgi?id=16026:
2372 tuple(3 * (T
.min_normal
* T
.epsilon
), T( .75), (T
.min_exp
- T
.mant_dig
) + 2)
2375 foreach (elem
; vals
)
2381 T v
= frexp(x
, eptr
);
2382 assert(isIdentical(e
, v
));
2383 assert(exp
== eptr
);
2386 static if (floatTraits
!(T
).realFormat
== RealFormat
.ieeeExtended
)
2388 static T
[3][] extendedvals
= [ // x,frexp,exp
2389 [0x1.a5f1c2eb3fe4efp
+73L, 0x1.A5F1C2EB3FE4EFp
-1L, 74], // normal
2390 [0x1.fa01712e8f0471ap
-1064L, 0x1.fa01712e8f0471ap
-1L, -1063],
2391 [T
.min_normal
, .5, -16381],
2392 [T
.min_normal
/2.0L, .5, -16382] // subnormal
2394 foreach (elem
; extendedvals
)
2398 int exp
= cast(int) elem
[2];
2400 T v
= frexp(x
, eptr
);
2401 assert(isIdentical(e
, v
));
2402 assert(exp
== eptr
);
2408 alias CtfeFrexpResult
= Tuple
!(real, int);
2409 static CtfeFrexpResult
ctfeFrexp(T
)(const T value
)
2412 auto significand
= frexp(value
, exp
);
2413 return CtfeFrexpResult(significand
, exp
);
2415 static foreach (T
; AliasSeq
!(real, double, float))
2417 enum Tuple
!(T
, T
, int)[] vals
= [ // x,frexp,exp
2418 tuple(T(0.0), T( 0.0 ), 0),
2419 tuple(T(-0.0), T( -0.0), 0),
2420 tuple(T(1.0), T( .5 ), 1),
2421 tuple(T(-1.0), T( -.5 ), 1),
2422 tuple(T(2.0), T( .5 ), 2),
2423 tuple(T(float.min_normal
/2.0f), T(.5), -126),
2424 tuple(T
.infinity
, T
.infinity
, int.max
),
2425 tuple(-T
.infinity
, -T
.infinity
, int.min
),
2426 tuple(T
.nan
, T
.nan
, int.min
),
2427 tuple(-T
.nan
, -T
.nan
, int.min
),
2429 // https://issues.dlang.org/show_bug.cgi?id=16026:
2430 tuple(3 * (T
.min_normal
* T
.epsilon
), T( .75), (T
.min_exp
- T
.mant_dig
) + 2)
2433 static foreach (elem
; vals
)
2435 static assert(ctfeFrexp(elem
[0]) is CtfeFrexpResult(elem
[1], elem
[2]));
2438 static if (floatTraits
!(T
).realFormat
== RealFormat
.ieeeExtended
)
2440 enum T
[3][] extendedvals
= [ // x,frexp,exp
2441 [0x1.a5f1c2eb3fe4efp
+73L, 0x1.A5F1C2EB3FE4EFp
-1L, 74], // normal
2442 [0x1.fa01712e8f0471ap
-1064L, 0x1.fa01712e8f0471ap
-1L, -1063],
2443 [T
.min_normal
, .5, -16381],
2444 [T
.min_normal
/2.0L, .5, -16382] // subnormal
2446 static foreach (elem
; extendedvals
)
2448 static assert(ctfeFrexp(elem
[0]) is CtfeFrexpResult(elem
[1], cast(int) elem
[2]));
2456 import std
.meta
: AliasSeq
;
2458 static foreach (T
; AliasSeq
!(real, double, float))
2463 auto c
= frexp(a
, exp
);
2464 auto d
= frexp(b
, exp
);
2469 /******************************************
2470 * Extracts the exponent of x as a signed integral value.
2472 * If x is not a special value, the result is the same as
2473 * $(D cast(int) logb(x)).
2476 * $(TR $(TH x) $(TH ilogb(x)) $(TH Range error?))
2477 * $(TR $(TD 0) $(TD FP_ILOGB0) $(TD yes))
2478 * $(TR $(TD $(PLUSMN)$(INFIN)) $(TD int.max) $(TD no))
2479 * $(TR $(TD $(NAN)) $(TD FP_ILOGBNAN) $(TD no))
2482 int ilogb(T
)(const T x
) @trusted pure nothrow @nogc
2483 if (isFloatingPoint
!T
)
2485 import std
.math
.traits
: floatTraits
, RealFormat
, MANTISSA_MSB
, MANTISSA_LSB
;
2487 import core
.bitop
: bsr;
2488 alias F
= floatTraits
!T
;
2493 ushort[T
.sizeof
/2] vu
;
2494 uint[T
.sizeof
/4] vui
;
2495 static if (T
.sizeof
>= 8)
2496 ulong[T
.sizeof
/8] vul
;
2501 int ex
= y
.vu
[F
.EXPPOS_SHORT
] & F
.EXPMASK
;
2502 static if (F
.realFormat
== RealFormat
.ieeeExtended ||
2503 F
.realFormat
== RealFormat
.ieeeExtended53
)
2507 // If exponent is non-zero
2508 if (ex
== F
.EXPMASK
) // infinity or NaN
2510 if (y
.vul
[0] & 0x7FFF_FFFF_FFFF_FFFF
) // NaN
2517 return ex
- F
.EXPBIAS
- 1;
2528 return ex
- F
.EXPBIAS
- T
.mant_dig
+ 1 + bsr(y
.vul
[0]);
2531 else static if (F
.realFormat
== RealFormat
.ieeeQuadruple
)
2533 if (ex
) // If exponent is non-zero
2535 if (ex
== F
.EXPMASK
)
2538 if (y
.vul
[MANTISSA_LSB
] |
( y
.vul
[MANTISSA_MSB
] & 0x0000_FFFF_FFFF_FFFF
)) // NaN
2545 return ex
- F
.EXPBIAS
- 1;
2548 else if ((y
.vul
[MANTISSA_LSB
] |
(y
.vul
[MANTISSA_MSB
] & 0x0000_FFFF_FFFF_FFFF
)) == 0)
2556 const ulong msb
= y
.vul
[MANTISSA_MSB
] & 0x0000_FFFF_FFFF_FFFF
;
2557 const ulong lsb
= y
.vul
[MANTISSA_LSB
];
2559 return ex
- F
.EXPBIAS
- T
.mant_dig
+ 1 + bsr(msb
) + 64;
2561 return ex
- F
.EXPBIAS
- T
.mant_dig
+ 1 + bsr(lsb
);
2564 else static if (F
.realFormat
== RealFormat
.ieeeDouble
)
2566 if (ex
) // If exponent is non-zero
2568 if (ex
== F
.EXPMASK
) // infinity or NaN
2570 if ((y
.vul
[0] & 0x7FFF_FFFF_FFFF_FFFF
) == 0x7FF0_0000_0000_0000) // +- infinity
2577 return ((ex
- F
.EXPBIAS
) >> 4) - 1;
2580 else if (!(y
.vul
[0] & 0x7FFF_FFFF_FFFF_FFFF
))
2588 enum MANTISSAMASK_64
= ((cast(ulong) F
.MANTISSAMASK_INT
) << 32) |
0xFFFF_FFFF
;
2589 return ((ex
- F
.EXPBIAS
) >> 4) - T
.mant_dig
+ 1 + bsr(y
.vul
[0] & MANTISSAMASK_64
);
2592 else static if (F
.realFormat
== RealFormat
.ieeeSingle
)
2594 if (ex
) // If exponent is non-zero
2596 if (ex
== F
.EXPMASK
) // infinity or NaN
2598 if ((y
.vui
[0] & 0x7FFF_FFFF
) == 0x7F80_0000) // +- infinity
2605 return ((ex
- F
.EXPBIAS
) >> 7) - 1;
2608 else if (!(y
.vui
[0] & 0x7FFF_FFFF
))
2616 const uint mantissa
= y
.vui
[0] & F
.MANTISSAMASK_INT
;
2617 return ((ex
- F
.EXPBIAS
) >> 7) - T
.mant_dig
+ 1 + bsr(mantissa
);
2620 else // static if (F.realFormat == RealFormat.ibmExtended)
2622 assert(0, "ilogb not implemented");
2626 int ilogb(T
)(const T x
) @safe pure nothrow @nogc
2627 if (isIntegral
!T
&& isUnsigned
!T
)
2629 import core
.bitop
: bsr;
2634 static assert(T
.sizeof
<= ulong.sizeof
, "integer size too large for the current ilogb implementation");
2639 int ilogb(T
)(const T x
) @safe pure nothrow @nogc
2640 if (isIntegral
!T
&& isSigned
!T
)
2642 import std
.traits
: Unsigned
;
2643 // Note: abs(x) can not be used because the return type is not Unsigned and
2644 // the return value would be wrong for x == int.min
2645 Unsigned
!T absx
= x
>= 0 ? x
: -x
;
2652 assert(ilogb(1) == 0);
2653 assert(ilogb(3) == 1);
2654 assert(ilogb(3.0) == 1);
2655 assert(ilogb(100_000_000) == 26);
2657 assert(ilogb(0) == FP_ILOGB0
);
2658 assert(ilogb(0.0) == FP_ILOGB0
);
2659 assert(ilogb(double.nan
) == FP_ILOGBNAN
);
2660 assert(ilogb(double.infinity
) == int.max
);
2664 Special return values of $(LREF ilogb).
2666 alias FP_ILOGB0
= core
.stdc
.math
.FP_ILOGB0
;
2668 alias FP_ILOGBNAN
= core
.stdc
.math
.FP_ILOGBNAN
;
2673 assert(ilogb(0) == FP_ILOGB0
);
2674 assert(ilogb(0.0) == FP_ILOGB0
);
2675 assert(ilogb(double.nan
) == FP_ILOGBNAN
);
2678 @safe nothrow @nogc unittest
2680 import std
.math
.traits
: floatTraits
, RealFormat
;
2681 import std
.math
.operations
: nextUp
;
2682 import std
.meta
: AliasSeq
;
2683 import std
.typecons
: Tuple
;
2684 static foreach (F
; AliasSeq
!(float, double, real))
2686 alias T
= Tuple
!(F
, int);
2687 T
[13] vals
= // x, ilogb(x)
2689 T( F
.nan
, FP_ILOGBNAN
),
2690 T( -F
.nan
, FP_ILOGBNAN
),
2691 T( F
.infinity
, int.max
),
2692 T( -F
.infinity
, int.max
),
2693 T( 0.0 , FP_ILOGB0
),
2694 T( -0.0 , FP_ILOGB0
),
2704 foreach (elem
; vals
)
2706 assert(ilogb(elem
[0]) == elem
[1]);
2710 // min_normal and subnormals
2711 assert(ilogb(-float.min_normal
) == -126);
2712 assert(ilogb(nextUp(-float.min_normal
)) == -127);
2713 assert(ilogb(nextUp(-float(0.0))) == -149);
2714 assert(ilogb(-double.min_normal
) == -1022);
2715 assert(ilogb(nextUp(-double.min_normal
)) == -1023);
2716 assert(ilogb(nextUp(-double(0.0))) == -1074);
2717 static if (floatTraits
!(real).realFormat
== RealFormat
.ieeeExtended
)
2719 assert(ilogb(-real.min_normal
) == -16382);
2720 assert(ilogb(nextUp(-real.min_normal
)) == -16383);
2721 assert(ilogb(nextUp(-real(0.0))) == -16445);
2723 else static if (floatTraits
!(real).realFormat
== RealFormat
.ieeeDouble
)
2725 assert(ilogb(-real.min_normal
) == -1022);
2726 assert(ilogb(nextUp(-real.min_normal
)) == -1023);
2727 assert(ilogb(nextUp(-real(0.0))) == -1074);
2730 // test integer types
2731 assert(ilogb(0) == FP_ILOGB0
);
2732 assert(ilogb(int.max
) == 30);
2733 assert(ilogb(int.min
) == 31);
2734 assert(ilogb(uint.max
) == 31);
2735 assert(ilogb(long.max
) == 62);
2736 assert(ilogb(long.min
) == 63);
2737 assert(ilogb(ulong.max
) == 63);
2740 /*******************************************
2741 * Compute n * 2$(SUPERSCRIPT exp)
2745 pragma(inline
, true)
2746 real ldexp(real n
, int exp
) @safe pure nothrow @nogc { return core
.math
.ldexp(n
, exp
); }
2748 pragma(inline
, true)
2749 double ldexp(double n
, int exp
) @safe pure nothrow @nogc { return core
.math
.ldexp(n
, exp
); }
2751 pragma(inline
, true)
2752 float ldexp(float n
, int exp
) @safe pure nothrow @nogc { return core
.math
.ldexp(n
, exp
); }
2755 @nogc @safe pure nothrow unittest
2757 import std
.meta
: AliasSeq
;
2758 static foreach (T
; AliasSeq
!(float, double, real))
2765 r
= ldexp(cast(T
) 3.0, cast(int) 3);
2775 @safe pure nothrow @nogc unittest
2777 import std
.math
.traits
: floatTraits
, RealFormat
;
2779 static if (floatTraits
!(real).realFormat
== RealFormat
.ieeeExtended ||
2780 floatTraits
!(real).realFormat
== RealFormat
.ieeeExtended53 ||
2781 floatTraits
!(real).realFormat
== RealFormat
.ieeeQuadruple
)
2783 assert(ldexp(1.0L, -16384) == 0x1p
-16384L);
2784 assert(ldexp(1.0L, -16382) == 0x1p
-16382L);
2786 real n
= frexp(0x1p
-16384L, x
);
2789 assert(ldexp(n
, x
)==0x1p
-16384L);
2791 else static if (floatTraits
!(real).realFormat
== RealFormat
.ieeeDouble
)
2793 assert(ldexp(1.0L, -1024) == 0x1p
-1024L);
2794 assert(ldexp(1.0L, -1022) == 0x1p
-1022L);
2796 real n
= frexp(0x1p
-1024L, x
);
2799 assert(ldexp(n
, x
)==0x1p
-1024L);
2801 else static assert(false, "Floating point type real not supported");
2804 /* workaround https://issues.dlang.org/show_bug.cgi?id=14718
2805 float parsing depends on platform strtold
2806 @safe pure nothrow @nogc unittest
2808 assert(ldexp(1.0, -1024) == 0x1p-1024);
2809 assert(ldexp(1.0, -1022) == 0x1p-1022);
2811 double n = frexp(0x1p-1024, x);
2814 assert(ldexp(n, x)==0x1p-1024);
2817 @safe pure nothrow @nogc unittest
2819 assert(ldexp(1.0f, -128) == 0x1p-128f);
2820 assert(ldexp(1.0f, -126) == 0x1p-126f);
2822 float n = frexp(0x1p-128f, x);
2825 assert(ldexp(n, x)==0x1p-128f);
2829 @safe @nogc nothrow unittest
2831 import std
.math
.operations
: isClose
;
2833 static real[3][] vals
= // value,exp,ldexp
2840 [ real.max
, int.max
, real.infinity
],
2841 [ real.max
, -int.max
, 0],
2842 [ real.min_normal
, -int.max
, 0],
2846 for (i
= 0; i
< vals
.length
; i
++)
2848 real x
= vals
[i
][0];
2849 int exp
= cast(int) vals
[i
][1];
2850 real z
= vals
[i
][2];
2851 real l
= ldexp(x
, exp
);
2853 assert(isClose(z
, l
, 1e-6));
2856 real function(real, int) pldexp
= &ldexp
;
2857 assert(pldexp
!= null);
2862 // Coefficients shared across log(), log2(), log10(), log1p().
2863 template LogCoeffs(T
)
2865 import std
.math
.traits
: floatTraits
, RealFormat
;
2867 static if (floatTraits
!T
.realFormat
== RealFormat
.ieeeQuadruple
)
2869 // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x)/Q(x)
2870 // Theoretical peak relative error = 5.3e-37
2871 static immutable real[13] logP
= [
2872 1.313572404063446165910279910527789794488E4L
,
2873 7.771154681358524243729929227226708890930E4L
,
2874 2.014652742082537582487669938141683759923E5L
,
2875 3.007007295140399532324943111654767187848E5L
,
2876 2.854829159639697837788887080758954924001E5L
,
2877 1.797628303815655343403735250238293741397E5L
,
2878 7.594356839258970405033155585486712125861E4L
,
2879 2.128857716871515081352991964243375186031E4L
,
2880 3.824952356185897735160588078446136783779E3L
,
2881 4.114517881637811823002128927449878962058E2L
,
2882 2.321125933898420063925789532045674660756E1L
,
2883 4.998469661968096229986658302195402690910E-1L,
2884 1.538612243596254322971797716843006400388E-6L
2886 static immutable real[13] logQ
= [
2887 3.940717212190338497730839731583397586124E4L
,
2888 2.626900195321832660448791748036714883242E5L
,
2889 7.777690340007566932935753241556479363645E5L
,
2890 1.347518538384329112529391120390701166528E6L
,
2891 1.514882452993549494932585972882995548426E6L
,
2892 1.158019977462989115839826904108208787040E6L
,
2893 6.132189329546557743179177159925690841200E5L
,
2894 2.248234257620569139969141618556349415120E5L
,
2895 5.605842085972455027590989944010492125825E4L
,
2896 9.147150349299596453976674231612674085381E3L
,
2897 9.104928120962988414618126155557301584078E2L
,
2898 4.839208193348159620282142911143429644326E1L
,
2902 // log2 uses the same coefficients as log.
2906 // log10 uses the same coefficients as log.
2907 alias log10P
= logP
;
2908 alias log10Q
= logQ
;
2910 // Coefficients for log(x) = z + z^^3 R(z^^2)/S(z^^2)
2911 // where z = 2(x-1)/(x+1)
2912 // Theoretical peak relative error = 1.1e-35
2913 static immutable real[6] logR
= [
2914 1.418134209872192732479751274970992665513E5L
,
2915 -8.977257995689735303686582344659576526998E4L
,
2916 2.048819892795278657810231591630928516206E4L
,
2917 -2.024301798136027039250415126250455056397E3L
,
2918 8.057002716646055371965756206836056074715E1L
,
2919 -8.828896441624934385266096344596648080902E-1L
2921 static immutable real[7] logS
= [
2922 1.701761051846631278975701529965589676574E6L
,
2923 -1.332535117259762928288745111081235577029E6L
,
2924 4.001557694070773974936904547424676279307E5L
,
2925 -5.748542087379434595104154610899551484314E4L
,
2926 3.998526750980007367835804959888064681098E3L
,
2927 -1.186359407982897997337150403816839480438E2L
,
2931 else static if (floatTraits
!T
.realFormat
== RealFormat
.ieeeExtended ||
2932 floatTraits
!T
.realFormat
== RealFormat
.ieeeExtended53
)
2934 // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x)/Q(x)
2935 // Theoretical peak relative error = 2.32e-20
2936 static immutable real[7] logP
= [
2937 2.0039553499201281259648E1L
,
2938 5.7112963590585538103336E1L
,
2939 6.0949667980987787057556E1L
,
2940 2.9911919328553073277375E1L
,
2941 6.5787325942061044846969E0L
,
2942 4.9854102823193375972212E-1L,
2943 4.5270000862445199635215E-5L,
2945 static immutable real[7] logQ
= [
2946 6.0118660497603843919306E1L
,
2947 2.1642788614495947685003E2L
,
2948 3.0909872225312059774938E2L
,
2949 2.2176239823732856465394E2L
,
2950 8.3047565967967209469434E1L
,
2951 1.5062909083469192043167E1L
,
2952 1.0000000000000000000000E0L
,
2955 // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x)/Q(x)
2956 // Theoretical peak relative error = 6.2e-22
2957 static immutable real[7] log2P
= [
2958 1.0747524399916215149070E2L
,
2959 3.4258224542413922935104E2L
,
2960 4.2401812743503691187826E2L
,
2961 2.5620629828144409632571E2L
,
2962 7.7671073698359539859595E1L
,
2963 1.0767376367209449010438E1L
,
2964 4.9962495940332550844739E-1L,
2966 static immutable real[8] log2Q
= [
2967 3.2242573199748645407652E2L
,
2968 1.2695660352705325274404E3L
,
2969 2.0307734695595183428202E3L
,
2970 1.6911722418503949084863E3L
,
2971 7.7952888181207260646090E2L
,
2972 1.9444210022760132894510E2L
,
2973 2.3479774160285863271658E1L
,
2974 1.0000000000000000000000E0
,
2977 // log10 uses the same coefficients as log2.
2978 alias log10P
= log2P
;
2979 alias log10Q
= log2Q
;
2981 // Coefficients for log(x) = z + z^^3 R(z^^2)/S(z^^2)
2982 // where z = 2(x-1)/(x+1)
2983 // Theoretical peak relative error = 6.16e-22
2984 static immutable real[4] logR
= [
2985 -3.5717684488096787370998E1L
,
2986 1.0777257190312272158094E1L
,
2987 -7.1990767473014147232598E-1L,
2988 1.9757429581415468984296E-3L,
2990 static immutable real[4] logS
= [
2991 -4.2861221385716144629696E2L
,
2992 1.9361891836232102174846E2L
,
2993 -2.6201045551331104417768E1L
,
2994 1.0000000000000000000000E0L
,
2997 else static if (floatTraits
!T
.realFormat
== RealFormat
.ieeeDouble
)
2999 // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x)/Q(x)
3000 static immutable double[6] logP
= [
3001 7.70838733755885391666E0
,
3002 1.79368678507819816313E1
,
3003 1.44989225341610930846E1
,
3004 4.70579119878881725854E0
,
3005 4.97494994976747001425E-1,
3006 1.01875663804580931796E-4,
3008 static immutable double[6] logQ
= [
3009 2.31251620126765340583E1
,
3010 7.11544750618563894466E1
,
3011 8.29875266912776603211E1
,
3012 4.52279145837532221105E1
,
3013 1.12873587189167450590E1
,
3014 1.00000000000000000000E0
,
3017 // log2 uses the same coefficients as log.
3021 // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x)/Q(x)
3022 static immutable double[7] logp1P
= [
3023 2.0039553499201281259648E1
,
3024 5.7112963590585538103336E1
,
3025 6.0949667980987787057556E1
,
3026 2.9911919328553073277375E1
,
3027 6.5787325942061044846969E0
,
3028 4.9854102823193375972212E-1,
3029 4.5270000862445199635215E-5,
3031 static immutable double[7] logp1Q
= [
3032 6.0118660497603843919306E1
,
3033 2.1642788614495947685003E2
,
3034 3.0909872225312059774938E2
,
3035 2.2176239823732856465394E2
,
3036 8.3047565967967209469434E1
,
3037 1.5062909083469192043167E1
,
3038 1.0000000000000000000000E0
,
3041 static immutable double[7] log10P
= [
3042 1.98892446572874072159E1
,
3043 5.67349287391754285487E1
,
3044 6.06127134467767258030E1
,
3045 2.97877425097986925891E1
,
3046 6.56312093769992875930E0
,
3047 4.98531067254050724270E-1,
3048 4.58482948458143443514E-5,
3050 static immutable double[7] log10Q
= [
3051 5.96677339718622216300E1
,
3052 2.14955586696422947765E2
,
3053 3.07254189979530058263E2
,
3054 2.20664384982121929218E2
,
3055 8.27410449222435217021E1
,
3056 1.50314182634250003249E1
,
3057 1.00000000000000000000E0
,
3060 // Coefficients for log(x) = z + z^^3 R(z)/S(z)
3061 // where z = 2(x-1)/(x+1)
3062 static immutable double[3] logR
= [
3063 -6.41409952958715622951E1
,
3064 1.63866645699558079767E1
,
3065 -7.89580278884799154124E-1,
3067 static immutable double[4] logS
= [
3068 -7.69691943550460008604E2
,
3069 3.12093766372244180303E2
,
3070 -3.56722798256324312549E1
,
3071 1.00000000000000000000E0
,
3074 else static if (floatTraits
!T
.realFormat
== RealFormat
.ieeeSingle
)
3076 // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x)
3077 static immutable float[9] logP
= [
3089 // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x)/Q(x)
3090 static immutable float[7] logp1P
= [
3099 static immutable float[7] logp1Q
= [
3109 // log2 and log10 uses the same coefficients as log.
3111 alias log10P
= logP
;
3114 static assert(0, "no coefficients for log()");
3118 /**************************************
3119 * Calculate the natural logarithm of x.
3122 * $(TR $(TH x) $(TH log(x)) $(TH divide by 0?) $(TH invalid?))
3123 * $(TR $(TD $(PLUSMN)0.0) $(TD -$(INFIN)) $(TD yes) $(TD no))
3124 * $(TR $(TD $(LT)0.0) $(TD $(NAN)) $(TD no) $(TD yes))
3125 * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) $(TD no) $(TD no))
3128 pragma(inline
, true)
3129 real log(real x
) @safe pure nothrow @nogc
3131 version (INLINE_YL2X
)
3133 import std
.math
.constants
: LN2
;
3134 return core
.math
.yl2x(x
, LN2
);
3141 pragma(inline
, true)
3142 double log(double x
) @safe pure nothrow @nogc { return __ctfe ?
cast(double) log(cast(real) x
) : logImpl(x
); }
3145 pragma(inline
, true)
3146 float log(float x
) @safe pure nothrow @nogc { return __ctfe ?
cast(float) log(cast(real) x
) : logImpl(x
); }
3148 // @@@DEPRECATED_[2.112.0]@@@
3149 deprecated("`std.math.exponential.log` called with argument types `(int)` matches both "
3150 ~ "`log(real)`, `log(double)`, and `log(float)`. Cast argument to floating point type instead.")
3151 real log(int x
) @safe pure nothrow @nogc { return log(cast(real) x
); }
3152 // @@@DEPRECATED_[2.112.0]@@@
3153 deprecated("`std.math.exponential.log` called with argument types `(uint)` matches both "
3154 ~ "`log(real)`, `log(double)`, and `log(float)`. Cast argument to floating point type instead.")
3155 real log(uint x
) @safe pure nothrow @nogc { return log(cast(real) x
); }
3156 // @@@DEPRECATED_[2.112.0]@@@
3157 deprecated("`std.math.exponential.log` called with argument types `(long)` matches both "
3158 ~ "`log(real)`, `log(double)`, and `log(float)`. Cast argument to floating point type instead.")
3159 real log(long x
) @safe pure nothrow @nogc { return log(cast(real) x
); }
3160 // @@@DEPRECATED_[2.112.0]@@@
3161 deprecated("`std.math.exponential.log` called with argument types `(ulong)` matches both "
3162 ~ "`log(real)`, `log(double)`, and `log(float)`. Cast argument to floating point type instead.")
3163 real log(ulong x
) @safe pure nothrow @nogc { return log(cast(real) x
); }
3166 @safe pure nothrow @nogc unittest
3168 import std
.math
.operations
: feqrel
;
3169 import std
.math
.constants
: E
;
3171 assert(feqrel(log(E
), 1) >= real.mant_dig
- 1);
3174 private T
logImpl(T
, bool LOG1P
= false)(T x
) @safe pure nothrow @nogc
3176 import std
.math
.constants
: SQRT1_2
;
3177 import std
.math
.algebraic
: poly
;
3178 import std
.math
.traits
: isInfinity
, isNaN
, signbit
, floatTraits
, RealFormat
;
3180 alias coeffs
= LogCoeffs
!T
;
3181 alias F
= floatTraits
!T
;
3189 static if (F
.realFormat
== RealFormat
.ieeeExtended ||
3190 F
.realFormat
== RealFormat
.ieeeExtended53 ||
3191 F
.realFormat
== RealFormat
.ieeeQuadruple
)
3194 enum T C1
= 6.93145751953125E-1L;
3195 enum T C2
= 1.428606820309417232121458176568075500134E-6L;
3197 else static if (F
.realFormat
== RealFormat
.ieeeDouble
)
3199 enum T C1
= 0.693359375;
3200 enum T C2
= -2.121944400546905827679e-4;
3202 else static if (F
.realFormat
== RealFormat
.ieeeSingle
)
3204 enum T C1
= 0.693359375;
3205 enum T C2
= -2.12194440e-4;
3208 static assert(0, "Not implemented for this architecture");
3213 if (isInfinity(x
) && !signbit(x
))
3220 // Separate mantissa from exponent.
3221 // Note, frexp is used so that denormal numbers will be handled properly.
3227 static if (F
.realFormat
== RealFormat
.ieeeDouble ||
3228 F
.realFormat
== RealFormat
.ieeeExtended ||
3229 F
.realFormat
== RealFormat
.ieeeExtended53 ||
3230 F
.realFormat
== RealFormat
.ieeeQuadruple
)
3232 // Logarithm using log(x) = z + z^^3 R(z) / S(z),
3233 // where z = 2(x - 1)/(x + 1)
3234 if ((exp
> 2) ||
(exp
< -2))
3237 { // 2(2x - 1)/(2x + 1)
3243 { // 2(x - 1)/(x + 1)
3250 z
= x
* (z
* poly(z
, coeffs
.logR
) / poly(z
, coeffs
.logS
));
3259 // Logarithm using log(1 + x) = x - .5x^^2 + x^^3 P(x) / Q(x)
3287 static if (F
.realFormat
== RealFormat
.ieeeSingle
)
3288 y
= x
* (z
* poly(x
, coeffs
.logP
));
3290 y
= x
* (z
* poly(x
, coeffs
.logP
) / poly(x
, coeffs
.logQ
));
3294 // Note, the sum of above terms does not exceed x/4,
3295 // so it contributes at most about 1/4 lsb to the error.
3302 @safe @nogc nothrow unittest
3304 import std
.math
.traits
: floatTraits
, RealFormat
;
3305 import std
.meta
: AliasSeq
;
3307 static void testLog(T
)(T
[2][] vals
)
3309 import std
.math
.operations
: isClose
;
3310 import std
.math
.traits
: isNaN
;
3311 foreach (ref pair
; vals
)
3314 assert(isNaN(log(pair
[0])));
3316 assert(isClose(log(pair
[0]), pair
[1]));
3319 static foreach (F
; AliasSeq
!(float, double, real))
3321 scope F
[2][] vals
= [
3322 [F(1), F(0x0p
+0)], [F(2), F(0x1.62e42fefa39ef358p
-1)],
3323 [F(4), F(0x1.62e42fefa39ef358p
+0)], [F(8), F(0x1.0a2b23f3bab73682p
+1)],
3324 [F(16), F(0x1.62e42fefa39ef358p
+1)], [F(32), F(0x1.bb9d3beb8c86b02ep
+1)],
3325 [F(64), F(0x1.0a2b23f3bab73682p
+2)], [F(128), F(0x1.3687a9f1af2b14ecp
+2)],
3326 [F(256), F(0x1.62e42fefa39ef358p
+2)], [F(512), F(0x1.8f40b5ed
9812d1c
2p
+2)],
3327 [F(1024), F(0x1.bb9d3beb8c86b02ep
+2)], [F(2048), F(0x1.e7f9c1e980fa8e98p
+2)],
3328 [F(3), F(0x1.193ea7aad030a976p
+0)], [F(5), F(0x1.9c041f7ed8d336bp
+0)],
3329 [F(7), F(0x1.f2272ae325a57546p
+0)], [F(15), F(0x1.5aa16394d481f014p
+1)],
3330 [F(17), F(0x1.6aa6bc1fa7f79cfp
+1)], [F(31), F(0x1.b78ce48912b59f12p
+1)],
3331 [F(33), F(0x1.bf8d8f4d5b8d1038p
+1)], [F(63), F(0x1.09291e8e3181b20ep
+2)],
3332 [F(65), F(0x1.0b292939429755ap
+2)], [F(-0), -F
.infinity
], [F(0), -F
.infinity
],
3333 [F(0.1), F(-0x1.26bb1bbb5551582ep
+1)], [F(0.25), F(-0x1.62e42fefa39ef358p
+0)],
3334 [F(0.75), F(-0x1.269621134db92784p
-2)], [F(0.875), F(-0x1.1178e8227e47bde4p
-3)],
3335 [F(10), F(0x1.26bb1bbb5551582ep
+1)], [F(100), F(0x1.26bb1bbb5551582ep
+2)],
3336 [F(10000), F(0x1.26bb1bbb5551582ep
+3)],
3341 float[2][16] vals
= [
3342 [float.nan
, float.nan
],[-float.nan
, float.nan
],
3343 [float.infinity
, float.infinity
], [-float.infinity
, float.nan
],
3344 [float.min_normal
, -0x1.5d58ap
+6f], [-float.min_normal
, float.nan
],
3345 [float.max
, 0x1.62e43p
+6f], [-float.max
, float.nan
],
3346 [float.min_normal
/ 2, -0x1.601e68p
+6f], [-float.min_normal
/ 2, float.nan
],
3347 [float.max
/ 2, 0x1.601e68p
+6f], [-float.max
/ 2, float.nan
],
3348 [float.min_normal
/ 3, -0x1.61bd9ap
+6f], [-float.min_normal
/ 3, float.nan
],
3349 [float.max
/ 3, 0x1.5e7f36p
+6f], [-float.max
/ 3, float.nan
],
3354 double[2][16] vals
= [
3355 [double.nan
, double.nan
],[-double.nan
, double.nan
],
3356 [double.infinity
, double.infinity
], [-double.infinity
, double.nan
],
3357 [double.min_normal
, -0x1.6232bdd7abcd
2p
+9], [-double.min_normal
, double.nan
],
3358 [double.max
, 0x1.62e42fefa39efp
+9], [-double.max
, double.nan
],
3359 [double.min_normal
/ 2, -0x1.628b76e
3a
7b61p
+9], [-double.min_normal
/ 2, double.nan
],
3360 [double.max
/ 2, 0x1.628b76e
3a
7b61p
+9], [-double.max
/ 2, double.nan
],
3361 [double.min_normal
/ 3, -0x1.62bf5d2b81354p
+9], [-double.min_normal
/ 3, double.nan
],
3362 [double.max
/ 3, 0x1.6257909bce
36ep
+9], [-double.max
/ 3, double.nan
],
3366 alias F
= floatTraits
!real;
3367 static if (F
.realFormat
== RealFormat
.ieeeExtended || F
.realFormat
== RealFormat
.ieeeQuadruple
)
3369 real[2][16] vals
= [
3370 [real.nan
, real.nan
],[-real.nan
, real.nan
],
3371 [real.infinity
, real.infinity
], [-real.infinity
, real.nan
],
3372 [real.min_normal
, -0x1.62d918ce
2421d66p
+13L], [-real.min_normal
, real.nan
],
3373 [real.max
, 0x1.62e42fefa39ef358p
+13L], [-real.max
, real.nan
],
3374 [real.min_normal
/ 2, -0x1.62dea
45ee
3e
064dcp
+13L], [-real.min_normal
/ 2, real.nan
],
3375 [real.max
/ 2, 0x1.62dea
45ee
3e
064dcp
+13L], [-real.max
/ 2, real.nan
],
3376 [real.min_normal
/ 3, -0x1.62e1e2c3617857e6p
+13L], [-real.min_normal
/ 3, real.nan
],
3377 [real.max
/ 3, 0x1.62db65fa
664871d2p
+13L], [-real.max
/ 3, real.nan
],
3383 /**************************************
3384 * Calculate the base-10 logarithm of x.
3387 * $(TR $(TH x) $(TH log10(x)) $(TH divide by 0?) $(TH invalid?))
3388 * $(TR $(TD $(PLUSMN)0.0) $(TD -$(INFIN)) $(TD yes) $(TD no))
3389 * $(TR $(TD $(LT)0.0) $(TD $(NAN)) $(TD no) $(TD yes))
3390 * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) $(TD no) $(TD no))
3393 pragma(inline
, true)
3394 real log10(real x
) @safe pure nothrow @nogc
3396 version (INLINE_YL2X
)
3398 import std
.math
.constants
: LOG2
;
3399 return core
.math
.yl2x(x
, LOG2
);
3402 return log10Impl(x
);
3406 pragma(inline
, true)
3407 double log10(double x
) @safe pure nothrow @nogc { return __ctfe ?
cast(double) log10(cast(real) x
) : log10Impl(x
); }
3410 pragma(inline
, true)
3411 float log10(float x
) @safe pure nothrow @nogc { return __ctfe ?
cast(float) log10(cast(real) x
) : log10Impl(x
); }
3413 // @@@DEPRECATED_[2.112.0]@@@
3414 deprecated("`std.math.exponential.log10` called with argument types `(int)` matches both "
3415 ~ "`log10(real)`, `log10(double)`, and `log10(float)`. Cast argument to floating point type instead.")
3416 real log10(int x
) @safe pure nothrow @nogc { return log10(cast(real) x
); }
3417 // @@@DEPRECATED_[2.112.0]@@@
3418 deprecated("`std.math.exponential.log10` called with argument types `(uint)` matches both "
3419 ~ "`log10(real)`, `log10(double)`, and `log10(float)`. Cast argument to floating point type instead.")
3420 real log10(uint x
) @safe pure nothrow @nogc { return log10(cast(real) x
); }
3421 // @@@DEPRECATED_[2.112.0]@@@
3422 deprecated("`std.math.exponential.log10` called with argument types `(long)` matches both "
3423 ~ "`log10(real)`, `log10(double)`, and `log10(float)`. Cast argument to floating point type instead.")
3424 real log10(long x
) @safe pure nothrow @nogc { return log10(cast(real) x
); }
3425 // @@@DEPRECATED_[2.112.0]@@@
3426 deprecated("`std.math.exponential.log10` called with argument types `(ulong)` matches both "
3427 ~ "`log10(real)`, `log10(double)`, and `log10(float)`. Cast argument to floating point type instead.")
3428 real log10(ulong x
) @safe pure nothrow @nogc { return log10(cast(real) x
); }
3431 @safe pure nothrow @nogc unittest
3433 import std
.math
.algebraic
: fabs;
3435 assert(fabs(log10(1000.0L) - 3) < .000001);
3438 @safe pure nothrow @nogc unittest
3440 import std
.math
.algebraic
: fabs;
3442 assert(fabs(log10(1000.0) - 3) < .000001);
3443 assert(fabs(log10(1000.0f) - 3) < .000001);
3446 private T
log10Impl(T
)(T x
) @safe pure nothrow @nogc
3448 import std
.math
.constants
: SQRT1_2
;
3449 import std
.math
.algebraic
: poly
;
3450 import std
.math
.traits
: isNaN
, isInfinity
, signbit
, floatTraits
, RealFormat
;
3452 alias coeffs
= LogCoeffs
!T
;
3453 alias F
= floatTraits
!T
;
3455 static if (F
.realFormat
== RealFormat
.ieeeExtended ||
3456 F
.realFormat
== RealFormat
.ieeeExtended53 ||
3457 F
.realFormat
== RealFormat
.ieeeQuadruple
)
3459 // log10(2) split into two parts.
3460 enum T L102A
= 0.3125L;
3461 enum T L102B
= -1.14700043360188047862611052755069732318101185E-2L;
3463 // log10(e) split into two parts.
3464 enum T L10EA
= 0.5L;
3465 enum T L10EB
= -6.570551809674817234887108108339491770560299E-2L;
3467 else static if (F
.realFormat
== RealFormat
.ieeeDouble ||
3468 F
.realFormat
== RealFormat
.ieeeSingle
)
3470 enum T L102A
= 3.0078125E-1;
3471 enum T L102B
= 2.48745663981195213739E-4;
3473 enum T L10EA
= 4.3359375E-1;
3474 enum T L10EB
= 7.00731903251827651129E-4;
3477 static assert(0, "Not implemented for this architecture");
3479 // Special cases are the same as for log.
3482 if (isInfinity(x
) && !signbit(x
))
3489 // Separate mantissa from exponent.
3490 // Note, frexp is used so that denormal numbers will be handled properly.
3496 static if (F
.realFormat
== RealFormat
.ieeeExtended ||
3497 F
.realFormat
== RealFormat
.ieeeExtended53 ||
3498 F
.realFormat
== RealFormat
.ieeeQuadruple
)
3500 // Logarithm using log(x) = z + z^^3 R(z) / S(z),
3501 // where z = 2(x - 1)/(x + 1)
3502 if ((exp
> 2) ||
(exp
< -2))
3505 { // 2(2x - 1)/(2x + 1)
3511 { // 2(x - 1)/(x + 1)
3518 y
= x
* (z
* poly(z
, coeffs
.logR
) / poly(z
, coeffs
.logS
));
3523 // Logarithm using log(1 + x) = x - .5x^^2 + x^^3 P(x) / Q(x)
3533 static if (F
.realFormat
== RealFormat
.ieeeSingle
)
3534 y
= x
* (z
* poly(x
, coeffs
.log10P
));
3536 y
= x
* (z
* poly(x
, coeffs
.log10P
) / poly(x
, coeffs
.log10Q
));
3539 // Multiply log of fraction by log10(e) and base 2 exponent by log10(2).
3540 // This sequence of operations is critical and it may be horribly
3541 // defeated by some compiler optimizers.
3553 @safe @nogc nothrow unittest
3555 import std
.math
.traits
: floatTraits
, RealFormat
;
3556 import std
.meta
: AliasSeq
;
3558 static void testLog10(T
)(T
[2][] vals
)
3560 import std
.math
.operations
: isClose
;
3561 import std
.math
.traits
: isNaN
;
3562 foreach (ref pair
; vals
)
3565 assert(isNaN(log10(pair
[0])));
3567 assert(isClose(log10(pair
[0]), pair
[1]));
3570 static foreach (F
; AliasSeq
!(float, double, real))
3572 scope F
[2][] vals
= [
3573 [F(1), F(0x0p
+0)], [F(2), F(0x1.34413509f79fef
32p
-2)],
3574 [F(4), F(0x1.34413509f79fef
32p
-1)], [F(8), F(0x1.ce61cf8ef36fe6cap
-1)],
3575 [F(16), F(0x1.34413509f79fef
32p
+0)], [F(32), F(0x1.8151824c7587eafep
+0)],
3576 [F(64), F(0x1.ce61cf8ef36fe6cap
+0)], [F(128), F(0x1.0db90e
68b8abf
14cp
+1)],
3577 [F(256), F(0x1.34413509f79fef
32p
+1)], [F(512), F(0x1.5ac95bab3693ed18p
+1)],
3578 [F(1024), F(0x1.8151824c7587eafep
+1)], [F(2048), F(0x1.a7d9a8edb47be8e4p
+1)],
3579 [F(3), F(0x1.e8927964fd5fd08cp
-2)], [F(5), F(0x1.65df657b04300868p
-1)],
3580 [F(7), F(0x1.b0b0b0b78cc3f296p
-1)], [F(15), F(0x1.2d145116c
16ff856p
+0)],
3581 [F(17), F(0x1.3afeb354b7d9731ap
+0)], [F(31), F(0x1.7dc
9e
145867e
62eap
+0)],
3582 [F(33), F(0x1.84bd545e
4baeddp
+0)], [F(63), F(0x1.cca1950e4511e192p
+0)],
3583 [F(65), F(0x1.d01b16f9433cf7b8p
+0)], [F(-0), -F
.infinity
], [F(0), -F
.infinity
],
3584 [F(0.1), F(-0x1p
+0)], [F(0.25), F(-0x1.34413509f79fef
32p
-1)],
3585 [F(0.75), F(-0x1.ffbfc2bbc7803758p
-4)], [F(0.875), F(-0x1.db11ed766abf432ep
-5)],
3586 [F(10), F(0x1p
+0)], [F(100), F(0x1p
+1)], [F(10000), F(0x1p
+2)],
3591 float[2][16] vals
= [
3592 [float.nan
, float.nan
],[-float.nan
, float.nan
],
3593 [float.infinity
, float.infinity
], [-float.infinity
, float.nan
],
3594 [float.min_normal
, -0x1.2f703p
+5f], [-float.min_normal
, float.nan
],
3595 [float.max
, 0x1.344136p
+5f], [-float.max
, float.nan
],
3596 [float.min_normal
/ 2, -0x1.31d8b2p
+5f], [-float.min_normal
/ 2, float.nan
],
3597 [float.max
/ 2, 0x1.31d8b2p
+5f], [-float.max
/ 2, float.nan
],
3598 [float.min_normal
/ 3, -0x1.334156p
+5f], [-float.min_normal
/ 3, float.nan
],
3599 [float.max
/ 3, 0x1.30701p
+5f], [-float.max
/ 3, float.nan
],
3604 double[2][16] vals
= [
3605 [double.nan
, double.nan
],[-double.nan
, double.nan
],
3606 [double.infinity
, double.infinity
], [-double.infinity
, double.nan
],
3607 [double.min_normal
, -0x1.33a7146f72a42p
+8], [-double.min_normal
, double.nan
],
3608 [double.max
, 0x1.34413509f79ffp
+8], [-double.max
, double.nan
],
3609 [double.min_normal
/ 2, -0x1.33f424bcb
522p
+8], [-double.min_normal
/ 2, double.nan
],
3610 [double.max
/ 2, 0x1.33f424bcb
522p
+8], [-double.max
/ 2, double.nan
],
3611 [double.min_normal
/ 3, -0x1.3421390dcbe
37p
+8], [-double.min_normal
/ 3, double.nan
],
3612 [double.max
/ 3, 0x1.33c7106b9e609p
+8], [-double.max
/ 3, double.nan
],
3616 alias F
= floatTraits
!real;
3617 static if (F
.realFormat
== RealFormat
.ieeeExtended || F
.realFormat
== RealFormat
.ieeeQuadruple
)
3619 real[2][16] vals
= [
3620 [real.nan
, real.nan
],[-real.nan
, real.nan
],
3621 [real.infinity
, real.infinity
], [-real.infinity
, real.nan
],
3622 [real.min_normal
, -0x1.343793004f503232p
+12L], [-real.min_normal
, real.nan
],
3623 [real.max
, 0x1.34413509f79fef
32p
+12L], [-real.max
, real.nan
],
3624 [real.min_normal
/ 2, -0x1.343c6405237810b2p
+12L], [-real.min_normal
/ 2, real.nan
],
3625 [real.max
/ 2, 0x1.343c6405237810b2p
+12L], [-real.max
/ 2, real.nan
],
3626 [real.min_normal
/ 3, -0x1.343f354a
34e
427bp
+12L], [-real.min_normal
/ 3, real.nan
],
3627 [real.max
/ 3, 0x1.343992c0120bf9b2p
+12L], [-real.max
/ 3, real.nan
],
3634 * Calculates the natural logarithm of 1 + x.
3636 * For very small x, log1p(x) will be more accurate than
3640 * $(TR $(TH x) $(TH log1p(x)) $(TH divide by 0?) $(TH invalid?))
3641 * $(TR $(TD $(PLUSMN)0.0) $(TD $(PLUSMN)0.0) $(TD no) $(TD no))
3642 * $(TR $(TD -1.0) $(TD -$(INFIN)) $(TD yes) $(TD no))
3643 * $(TR $(TD $(LT)-1.0) $(TD -$(NAN)) $(TD no) $(TD yes))
3644 * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) $(TD no) $(TD no))
3647 pragma(inline
, true)
3648 real log1p(real x
) @safe pure nothrow @nogc
3650 version (INLINE_YL2X
)
3652 // On x87, yl2xp1 is valid if and only if -0.5 <= lg(x) <= 0.5,
3653 // ie if -0.29 <= x <= 0.414
3654 import std
.math
.constants
: LN2
;
3655 return (core
.math
.fabs(x
) <= 0.25) ? core
.math
.yl2xp1(x
, LN2
) : core
.math
.yl2x(x
+1, LN2
);
3658 return log1pImpl(x
);
3662 pragma(inline
, true)
3663 double log1p(double x
) @safe pure nothrow @nogc { return __ctfe ?
cast(double) log1p(cast(real) x
) : log1pImpl(x
); }
3666 pragma(inline
, true)
3667 float log1p(float x
) @safe pure nothrow @nogc { return __ctfe ?
cast(float) log1p(cast(real) x
) : log1pImpl(x
); }
3669 // @@@DEPRECATED_[2.112.0]@@@
3670 deprecated("`std.math.exponential.log1p` called with argument types `(int)` matches both "
3671 ~ "`log1p(real)`, `log1p(double)`, and `log1p(float)`. Cast argument to floating point type instead.")
3672 real log1p(int x
) @safe pure nothrow @nogc { return log1p(cast(real) x
); }
3673 // @@@DEPRECATED_[2.112.0]@@@
3674 deprecated("`std.math.exponential.log1p` called with argument types `(uint)` matches both "
3675 ~ "`log1p(real)`, `log1p(double)`, and `log1p(float)`. Cast argument to floating point type instead.")
3676 real log1p(uint x
) @safe pure nothrow @nogc { return log1p(cast(real) x
); }
3677 // @@@DEPRECATED_[2.112.0]@@@
3678 deprecated("`std.math.exponential.log1p` called with argument types `(long)` matches both "
3679 ~ "`log1p(real)`, `log1p(double)`, and `log1p(float)`. Cast argument to floating point type instead.")
3680 real log1p(long x
) @safe pure nothrow @nogc { return log1p(cast(real) x
); }
3681 // @@@DEPRECATED_[2.112.0]@@@
3682 deprecated("`std.math.exponential.log1p` called with argument types `(ulong)` matches both "
3683 ~ "`log1p(real)`, `log1p(double)`, and `log1p(float)`. Cast argument to floating point type instead.")
3684 real log1p(ulong x
) @safe pure nothrow @nogc { return log1p(cast(real) x
); }
3689 import std
.math
.traits
: isIdentical
, isNaN
;
3690 import std
.math
.operations
: feqrel
;
3692 assert(isIdentical(log1p(0.0), 0.0));
3693 assert(log1p(1.0).feqrel(0.69314) > 16);
3695 assert(log1p(-1.0) == -real.infinity
);
3696 assert(isNaN(log1p(-2.0)));
3697 assert(log1p(real.nan
) is real.nan
);
3698 assert(log1p(-real.nan
) is -real.nan
);
3699 assert(log1p(real.infinity
) == real.infinity
);
3702 private T
log1pImpl(T
)(T x
) @safe pure nothrow @nogc
3704 import std
.math
.traits
: isNaN
, isInfinity
, signbit
;
3705 import std
.math
.algebraic
: poly
;
3706 import std
.math
.constants
: SQRT1_2
, SQRT2
;
3707 import std
.math
.traits
: floatTraits
, RealFormat
;
3710 if (isNaN(x
) || x
== 0.0)
3712 if (isInfinity(x
) && !signbit(x
))
3719 alias F
= floatTraits
!T
;
3720 static if (F
.realFormat
== RealFormat
.ieeeSingle ||
3721 F
.realFormat
== RealFormat
.ieeeDouble
)
3723 // When the input is within the range 1/sqrt(2) <= x+1 <= sqrt(2), compute
3724 // log1p inline. Forwarding to log() would otherwise result in inaccuracies.
3725 const T xp1
= x
+ 1.0;
3726 if (xp1
>= SQRT1_2
&& xp1
<= SQRT2
)
3728 alias coeffs
= LogCoeffs
!T
;
3730 T px
= poly(x
, coeffs
.logp1P
);
3731 T qx
= poly(x
, coeffs
.logp1Q
);
3733 qx
= x
+ ((cast(T
) -0.5) * xx
+ x
* (xx
* px
/ qx
));
3738 return logImpl
!(T
, true)(x
);
3741 @safe @nogc nothrow unittest
3743 import std
.math
.traits
: floatTraits
, RealFormat
;
3744 import std
.meta
: AliasSeq
;
3746 static void testLog1p(T
)(T
[2][] vals
)
3748 import std
.math
.operations
: isClose
;
3749 import std
.math
.traits
: isNaN
;
3750 foreach (ref pair
; vals
)
3753 assert(isNaN(log1p(pair
[0])));
3755 assert(isClose(log1p(pair
[0]), pair
[1]));
3758 static foreach (F
; AliasSeq
!(float, double, real))
3760 scope F
[2][] vals
= [
3761 [F(1), F(0x1.62e42fefa39ef358p
-1)], [F(2), F(0x1.193ea7aad030a976p
+0)],
3762 [F(4), F(0x1.9c041f7ed8d336bp
+0)], [F(8), F(0x1.193ea7aad030a976p
+1)],
3763 [F(16), F(0x1.6aa6bc1fa7f79cfp
+1)], [F(32), F(0x1.bf8d8f4d5b8d1038p
+1)],
3764 [F(64), F(0x1.0b292939429755ap
+2)], [F(128), F(0x1.37072a9b5b6cb31p
+2)],
3765 [F(256), F(0x1.63241004e9010ad8p
+2)], [F(512), F(0x1.8f60adf
041bde
2a
8p
+2)],
3766 [F(1024), F(0x1.bbad39ebe1cc08b6p
+2)], [F(2048), F(0x1.e801c1698ba4395cp
+2)],
3767 [F(3), F(0x1.62e42fefa39ef358p
+0)], [F(5), F(0x1.cab0bfa2a2002322p
+0)],
3768 [F(7), F(0x1.0a2b23f3bab73682p
+1)], [F(15), F(0x1.62e42fefa39ef358p
+1)],
3769 [F(17), F(0x1.71f7b3a
6b918664cp
+1)], [F(31), F(0x1.bb9d3beb8c86b02ep
+1)],
3770 [F(33), F(0x1.c35fc81b90df59c6p
+1)], [F(63), F(0x1.0a2b23f3bab73682p
+2)],
3771 [F(65), F(0x1.0c234da4a23a6686p
+2)], [F(-0), F(-0x0p
+0)], [F(0), F(0x0p
+0)],
3772 [F(0.1), F(0x1.8663f793c
46c
69cp
-4)], [F(0.25), F(0x1.c8ff7c79a9a21ac4p
-3)],
3773 [F(0.75), F(0x1.1e85f5e7040d03ep
-1)], [F(0.875), F(0x1.41d8fe
84672ae
646p
-1)],
3774 [F(10), F(0x1.32ee3b77f374bb7cp
+1)], [F(100), F(0x1.275e2271bba30be4p
+2)],
3775 [F(10000), F(0x1.26bbed
6fbd84182ep
+3)],
3780 float[2][16] vals
= [
3781 [float.nan
, float.nan
],[-float.nan
, float.nan
],
3782 [float.infinity
, float.infinity
], [-float.infinity
, float.nan
],
3783 [float.min_normal
, 0x1p
-126f], [-float.min_normal
, -0x1p
-126f],
3784 [float.max
, 0x1.62e43p
+6f], [-float.max
, float.nan
],
3785 [float.min_normal
/ 2, 0x0.8p
-126f], [-float.min_normal
/ 2, -0x0.8p
-126f],
3786 [float.max
/ 2, 0x1.601e68p
+6f], [-float.max
/ 2, float.nan
],
3787 [float.min_normal
/ 3, 0x0.555556p
-126f], [-float.min_normal
/ 3, -0x0.555556p
-126f],
3788 [float.max
/ 3, 0x1.5e7f36p
+6f], [-float.max
/ 3, float.nan
],
3793 double[2][16] vals
= [
3794 [double.nan
, double.nan
],[-double.nan
, double.nan
],
3795 [double.infinity
, double.infinity
], [-double.infinity
, double.nan
],
3796 [double.min_normal
, 0x1p
-1022], [-double.min_normal
, -0x1p
-1022],
3797 [double.max
, 0x1.62e42fefa39efp
+9], [-double.max
, double.nan
],
3798 [double.min_normal
/ 2, 0x0.8p
-1022], [-double.min_normal
/ 2, -0x0.8p
-1022],
3799 [double.max
/ 2, 0x1.628b76e
3a
7b61p
+9], [-double.max
/ 2, double.nan
],
3800 [double.min_normal
/ 3, 0x0.5555555555555p
-1022], [-double.min_normal
/ 3, -0x0.5555555555555p
-1022],
3801 [double.max
/ 3, 0x1.6257909bce
36ep
+9], [-double.max
/ 3, double.nan
],
3805 alias F
= floatTraits
!real;
3806 static if (F
.realFormat
== RealFormat
.ieeeExtended || F
.realFormat
== RealFormat
.ieeeQuadruple
)
3808 real[2][16] vals
= [
3809 [real.nan
, real.nan
],[-real.nan
, real.nan
],
3810 [real.infinity
, real.infinity
], [-real.infinity
, real.nan
],
3811 [real.min_normal
, 0x1p
-16382L], [-real.min_normal
, -0x1p
-16382L],
3812 [real.max
, 0x1.62e42fefa39ef358p
+13L], [-real.max
, real.nan
],
3813 [real.min_normal
/ 2, 0x0.8p
-16382L], [-real.min_normal
/ 2, -0x0.8p
-16382L],
3814 [real.max
/ 2, 0x1.62dea
45ee
3e
064dcp
+13L], [-real.max
/ 2, real.nan
],
3815 [real.min_normal
/ 3, 0x0.5555555555555556p
-16382L], [-real.min_normal
/ 3, -0x0.5555555555555556p
-16382L],
3816 [real.max
/ 3, 0x1.62db65fa
664871d2p
+13L], [-real.max
/ 3, real.nan
],
3822 /***************************************
3823 * Calculates the base-2 logarithm of x:
3827 * $(TR $(TH x) $(TH log2(x)) $(TH divide by 0?) $(TH invalid?))
3828 * $(TR $(TD $(PLUSMN)0.0) $(TD -$(INFIN)) $(TD yes) $(TD no) )
3829 * $(TR $(TD $(LT)0.0) $(TD $(NAN)) $(TD no) $(TD yes) )
3830 * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) $(TD no) $(TD no) )
3833 pragma(inline
, true)
3834 real log2(real x
) @safe pure nothrow @nogc
3836 version (INLINE_YL2X
)
3837 return core
.math
.yl2x(x
, 1.0L);
3843 pragma(inline
, true)
3844 double log2(double x
) @safe pure nothrow @nogc { return __ctfe ?
cast(double) log2(cast(real) x
) : log2Impl(x
); }
3847 pragma(inline
, true)
3848 float log2(float x
) @safe pure nothrow @nogc { return __ctfe ?
cast(float) log2(cast(real) x
) : log2Impl(x
); }
3850 // @@@DEPRECATED_[2.112.0]@@@
3851 deprecated("`std.math.exponential.log2` called with argument types `(int)` matches both "
3852 ~ "`log2(real)`, `log2(double)`, and `log2(float)`. Cast argument to floating point type instead.")
3853 real log2(int x
) @safe pure nothrow @nogc { return log2(cast(real) x
); }
3854 // @@@DEPRECATED_[2.112.0]@@@
3855 deprecated("`std.math.exponential.log2` called with argument types `(uint)` matches both "
3856 ~ "`log2(real)`, `log2(double)`, and `log2(float)`. Cast argument to floating point type instead.")
3857 real log2(uint x
) @safe pure nothrow @nogc { return log2(cast(real) x
); }
3858 // @@@DEPRECATED_[2.112.0]@@@
3859 deprecated("`std.math.exponential.log2` called with argument types `(long)` matches both "
3860 ~ "`log2(real)`, `log2(double)`, and `log2(float)`. Cast argument to floating point type instead.")
3861 real log2(long x
) @safe pure nothrow @nogc { return log2(cast(real) x
); }
3862 // @@@DEPRECATED_[2.112.0]@@@
3863 deprecated("`std.math.exponential.log2` called with argument types `(ulong)` matches both "
3864 ~ "`log2(real)`, `log2(double)`, and `log2(float)`. Cast argument to floating point type instead.")
3865 real log2(ulong x
) @safe pure nothrow @nogc { return log2(cast(real) x
); }
3870 import std
.math
.operations
: isClose
;
3872 assert(isClose(log2(1024.0L), 10));
3875 @safe @nogc nothrow unittest
3877 import std
.math
.operations
: isClose
;
3879 // check if values are equal to 19 decimal digits of precision
3880 assert(isClose(log2(1024.0L), 10, 1e-18));
3883 private T
log2Impl(T
)(T x
) @safe pure nothrow @nogc
3885 import std
.math
.traits
: isNaN
, isInfinity
, signbit
;
3886 import std
.math
.constants
: SQRT1_2
, LOG2E
;
3887 import std
.math
.algebraic
: poly
;
3888 import std
.math
.traits
: floatTraits
, RealFormat
;
3890 alias coeffs
= LogCoeffs
!T
;
3891 alias F
= floatTraits
!T
;
3893 // Special cases are the same as for log.
3896 if (isInfinity(x
) && !signbit(x
))
3903 // Separate mantissa from exponent.
3904 // Note, frexp is used so that denormal numbers will be handled properly.
3910 static if (F
.realFormat
== RealFormat
.ieeeDouble ||
3911 F
.realFormat
== RealFormat
.ieeeExtended ||
3912 F
.realFormat
== RealFormat
.ieeeExtended53 ||
3913 F
.realFormat
== RealFormat
.ieeeQuadruple
)
3915 // Logarithm using log(x) = z + z^^3 R(z) / S(z),
3916 // where z = 2(x - 1)/(x + 1)
3917 if ((exp
> 2) ||
(exp
< -2))
3920 { // 2(2x - 1)/(2x + 1)
3926 { // 2(x - 1)/(x + 1)
3933 y
= x
* (z
* poly(z
, coeffs
.logR
) / poly(z
, coeffs
.logS
));
3938 // Logarithm using log(1 + x) = x - .5x^^2 + x^^3 P(x) / Q(x)
3948 static if (F
.realFormat
== RealFormat
.ieeeSingle
)
3949 y
= x
* (z
* poly(x
, coeffs
.log2P
));
3951 y
= x
* (z
* poly(x
, coeffs
.log2P
) / poly(x
, coeffs
.log2Q
));
3954 // Multiply log of fraction by log10(e) and base 2 exponent by log10(2).
3955 // This sequence of operations is critical and it may be horribly
3956 // defeated by some compiler optimizers.
3958 z
= y
* (LOG2E
- 1.0);
3959 z
+= x
* (LOG2E
- 1.0);
3967 @safe @nogc nothrow unittest
3969 import std
.math
.traits
: floatTraits
, RealFormat
;
3970 import std
.meta
: AliasSeq
;
3972 static void testLog2(T
)(T
[2][] vals
)
3974 import std
.math
.operations
: isClose
;
3975 import std
.math
.traits
: isNaN
;
3976 foreach (ref pair
; vals
)
3979 assert(isNaN(log2(pair
[0])));
3981 assert(isClose(log2(pair
[0]), pair
[1]));
3984 static foreach (F
; AliasSeq
!(float, double, real))
3986 scope F
[2][] vals
= [
3987 [F(1), F(0x0p
+0)], [F(2), F(0x1p
+0)],
3988 [F(4), F(0x1p
+1)], [F(8), F(0x1.8p
+1)],
3989 [F(16), F(0x1p
+2)], [F(32), F(0x1.4p
+2)],
3990 [F(64), F(0x1.8p
+2)], [F(128), F(0x1.cp
+2)],
3991 [F(256), F(0x1p
+3)], [F(512), F(0x1.2p
+3)],
3992 [F(1024), F(0x1.4p
+3)], [F(2048), F(0x1.6p
+3)],
3993 [F(3), F(0x1.95c01a39fbd687ap
+0)], [F(5), F(0x1.2934f0979a
3715fcp
+1)],
3994 [F(7), F(0x1.675767f54042cd
9ap
+1)], [F(15), F(0x1.f414fdb4982259ccp
+1)],
3995 [F(17), F(0x1.0598fdbeb
244c
5ap
+2)], [F(31), F(0x1.3d118d66c
4d4e
554p
+2)],
3996 [F(33), F(0x1.42d75a
6eb
1dfb0e
6p
+2)], [F(63), F(0x1.7e8bc1179e0caa9cp
+2)],
3997 [F(65), F(0x1.816e79685c2d2298p
+2)], [F(-0), -F
.infinity
], [F(0), -F
.infinity
],
3998 [F(0.1), F(-0x1.a934f0979a3715fcp
+1)], [F(0.25), F(-0x1p
+1)],
3999 [F(0.75), F(-0x1.a8ff971810a5e182p
-2)], [F(0.875), F(-0x1.8a8980abfbd32668p
-3)],
4000 [F(10), F(0x1.a934f0979a3715fcp
+1)], [F(100), F(0x1.a934f0979a3715fcp
+2)],
4001 [F(10000), F(0x1.a934f0979a3715fcp
+3)],
4006 float[2][16] vals
= [
4007 [float.nan
, float.nan
],[-float.nan
, float.nan
],
4008 [float.infinity
, float.infinity
], [-float.infinity
, float.nan
],
4009 [float.min_normal
, -0x1.f8p
+6f], [-float.min_normal
, float.nan
],
4010 [float.max
, 0x1p
+7f], [-float.max
, float.nan
],
4011 [float.min_normal
/ 2, -0x1.fcp
+6f], [-float.min_normal
/ 2, float.nan
],
4012 [float.max
/ 2, 0x1.fcp
+6f], [-float.max
/ 2, float.nan
],
4013 [float.min_normal
/ 3, -0x1.fe57p
+6f], [-float.min_normal
/ 3, float.nan
],
4014 [float.max
/ 3, 0x1.f9a9p
+6f], [-float.max
/ 3, float.nan
],
4019 double[2][16] vals
= [
4020 [double.nan
, double.nan
],[-double.nan
, double.nan
],
4021 [double.infinity
, double.infinity
], [-double.infinity
, double.nan
],
4022 [double.min_normal
, -0x1.ffp
+9], [-double.min_normal
, double.nan
],
4023 [double.max
, 0x1p
+10], [-double.max
, double.nan
],
4024 [double.min_normal
/ 2, -0x1.ff8p
+9], [-double.min_normal
/ 2, double.nan
],
4025 [double.max
/ 2, 0x1.ff8p
+9], [-double.max
/ 2, double.nan
],
4026 [double.min_normal
/ 3, -0x1.ffcae00d1cfdfp
+9], [-double.min_normal
/ 3, double.nan
],
4027 [double.max
/ 3, 0x1.ff351ff2e3021p
+9], [-double.max
/ 3, double.nan
],
4031 alias F
= floatTraits
!real;
4032 static if (F
.realFormat
== RealFormat
.ieeeExtended || F
.realFormat
== RealFormat
.ieeeQuadruple
)
4034 real[2][16] vals
= [
4035 [real.nan
, real.nan
],[-real.nan
, real.nan
],
4036 [real.infinity
, real.infinity
], [-real.infinity
, real.nan
],
4037 [real.min_normal
, -0x1.fffp
+13L], [-real.min_normal
, real.nan
],
4038 [real.max
, 0x1p
+14L], [-real.max
, real.nan
],
4039 [real.min_normal
/ 2, -0x1.fff8p
+13L], [-real.min_normal
/ 2, real.nan
],
4040 [real.max
/ 2, 0x1.fff8p
+13L], [-real.max
/ 2, real.nan
],
4041 [real.min_normal
/ 3, -0x1.fffcae00d1cfdeb4p
+13L], [-real.min_normal
/ 3, real.nan
],
4042 [real.max
/ 3, 0x1.fff351ff2e30214cp
+13L], [-real.max
/ 3, real.nan
],
4048 /*****************************************
4049 * Extracts the exponent of x as a signed integral value.
4051 * If x is subnormal, it is treated as if it were normalized.
4052 * For a positive, finite x:
4054 * 1 $(LT)= $(I x) * FLT_RADIX$(SUPERSCRIPT -logb(x)) $(LT) FLT_RADIX
4057 * $(TR $(TH x) $(TH logb(x)) $(TH divide by 0?) )
4058 * $(TR $(TD $(PLUSMN)$(INFIN)) $(TD +$(INFIN)) $(TD no))
4059 * $(TR $(TD $(PLUSMN)0.0) $(TD -$(INFIN)) $(TD yes) )
4062 pragma(inline
, true)
4063 real logb(real x
) @trusted pure nothrow @nogc
4065 version (InlineAsm_X87_MSVC
)
4072 pragma(inline
, true)
4073 double logb(double x
) @trusted pure nothrow @nogc { return logbImpl(x
); }
4076 pragma(inline
, true)
4077 float logb(float x
) @trusted pure nothrow @nogc { return logbImpl(x
); }
4080 @safe @nogc nothrow unittest
4082 assert(logb(1.0) == 0);
4083 assert(logb(100.0) == 6);
4085 assert(logb(0.0) == -real.infinity
);
4086 assert(logb(real.infinity
) == real.infinity
);
4087 assert(logb(-real.infinity
) == real.infinity
);
4090 @safe @nogc nothrow unittest
4092 import std
.meta
: AliasSeq
;
4093 import std
.typecons
: Tuple
;
4094 import std
.math
.traits
: isNaN
;
4095 static foreach (F
; AliasSeq
!(float, double, real))
4097 alias T
= Tuple
!(F
, F
);
4098 T
[17] vals
= // x, logb(x)
4102 T(0.0 , -F
.infinity
),
4103 T(-0.0 , -F
.infinity
),
4106 T(0x0.1p
-127 , -131 ),
4107 T(0x0.01p
-127 , -135 ),
4108 T(0x0.011p
-127 , -135 ),
4111 T(F
.infinity
, F
.infinity
),
4112 T(-F
.infinity
, F
.infinity
),
4113 T(F
.min_normal
, F
.min_exp
-1),
4114 T(-F
.min_normal
, F
.min_exp
-1),
4115 T(F
.max
, F
.max_exp
-1),
4116 T(-F
.max
, F
.max_exp
-1),
4119 foreach (elem
; vals
)
4122 assert(isNaN(logb(elem
[1])));
4124 assert(logb(elem
[0]) == elem
[1]);
4129 version (InlineAsm_X87_MSVC
)
4130 private T
logbAsm(T
)(T x
) @trusted pure nothrow @nogc
4134 asm pure nothrow @nogc
4137 fld real ptr
[RCX
] ;
4145 asm pure nothrow @nogc
4154 private T
logbImpl(T
)(T x
) @trusted pure nothrow @nogc
4156 import std
.math
.traits
: isFinite
;
4158 // Handle special cases.
4162 return -1 / (x
* x
);
4167 @safe @nogc nothrow unittest
4169 import std
.math
.traits
: floatTraits
, RealFormat
;
4170 import std
.meta
: AliasSeq
;
4172 static void testLogb(T
)(T
[2][] vals
)
4174 import std
.math
.operations
: isClose
;
4175 import std
.math
.traits
: isNaN
;
4176 foreach (ref pair
; vals
)
4179 assert(isNaN(logb(pair
[0])));
4181 assert(isClose(logb(pair
[0]), pair
[1]));
4184 static foreach (F
; AliasSeq
!(float, double, real))
4186 scope F
[2][] vals
= [
4187 [F(1), F(0x0p
+0)], [F(2), F(0x1p
+0)],
4188 [F(4), F(0x1p
+1)], [F(8), F(0x1.8p
+1)],
4189 [F(16), F(0x1p
+2)], [F(32), F(0x1.4p
+2)],
4190 [F(64), F(0x1.8p
+2)], [F(128), F(0x1.cp
+2)],
4191 [F(256), F(0x1p
+3)], [F(512), F(0x1.2p
+3)],
4192 [F(1024), F(0x1.4p
+3)], [F(2048), F(0x1.6p
+3)],
4193 [F(3), F(0x1p
+0)], [F(5), F(0x1p
+1)],
4194 [F(7), F(0x1p
+1)], [F(15), F(0x1.8p
+1)],
4195 [F(17), F(0x1p
+2)], [F(31), F(0x1p
+2)],
4196 [F(33), F(0x1.4p
+2)], [F(63), F(0x1.4p
+2)],
4197 [F(65), F(0x1.8p
+2)], [F(-0), -F
.infinity
], [F(0), -F
.infinity
],
4198 [F(0.1), F(-0x1p
+2)], [F(0.25), F(-0x1p
+1)],
4199 [F(0.75), F(-0x1p
+0)], [F(0.875), F(-0x1p
+0)],
4200 [F(10), F(0x1.8p
+1)], [F(100), F(0x1.8p
+2)],
4201 [F(10000), F(0x1.ap
+3)],
4206 float[2][16] vals
= [
4207 [float.nan
, float.nan
],[-float.nan
, float.nan
],
4208 [float.infinity
, float.infinity
], [-float.infinity
, float.infinity
],
4209 [float.min_normal
, -0x1.f8p
+6f], [-float.min_normal
, -0x1.f8p
+6f],
4210 [float.max
, 0x1.fcp
+6f], [-float.max
, 0x1.fcp
+6f],
4211 [float.min_normal
/ 2, -0x1.fcp
+6f], [-float.min_normal
/ 2, -0x1.fcp
+6f],
4212 [float.max
/ 2, 0x1.f8p
+6f], [-float.max
/ 2, 0x1.f8p
+6f],
4213 [float.min_normal
/ 3, -0x1p
+7f], [-float.min_normal
/ 3, -0x1p
+7f],
4214 [float.max
/ 3, 0x1.f8p
+6f], [-float.max
/ 3, 0x1.f8p
+6f],
4219 double[2][16] vals
= [
4220 [double.nan
, double.nan
],[-double.nan
, double.nan
],
4221 [double.infinity
, double.infinity
], [-double.infinity
, double.infinity
],
4222 [double.min_normal
, -0x1.ffp
+9], [-double.min_normal
, -0x1.ffp
+9],
4223 [double.max
, 0x1.ff8p
+9], [-double.max
, 0x1.ff8p
+9],
4224 [double.min_normal
/ 2, -0x1.ff8p
+9], [-double.min_normal
/ 2, -0x1.ff8p
+9],
4225 [double.max
/ 2, 0x1.ffp
+9], [-double.max
/ 2, 0x1.ffp
+9],
4226 [double.min_normal
/ 3, -0x1p
+10], [-double.min_normal
/ 3, -0x1p
+10],
4227 [double.max
/ 3, 0x1.ffp
+9], [-double.max
/ 3, 0x1.ffp
+9],
4231 alias F
= floatTraits
!real;
4232 static if (F
.realFormat
== RealFormat
.ieeeExtended || F
.realFormat
== RealFormat
.ieeeQuadruple
)
4234 real[2][16] vals
= [
4235 [real.nan
, real.nan
],[-real.nan
, real.nan
],
4236 [real.infinity
, real.infinity
], [-real.infinity
, real.infinity
],
4237 [real.min_normal
, -0x1.fffp
+13L], [-real.min_normal
, -0x1.fffp
+13L],
4238 [real.max
, 0x1.fff8p
+13L], [-real.max
, 0x1.fff8p
+13L],
4239 [real.min_normal
/ 2, -0x1.fff8p
+13L], [-real.min_normal
/ 2, -0x1.fff8p
+13L],
4240 [real.max
/ 2, 0x1.fffp
+13L], [-real.max
/ 2, 0x1.fffp
+13L],
4241 [real.min_normal
/ 3, -0x1p
+14L], [-real.min_normal
/ 3, -0x1p
+14L],
4242 [real.max
/ 3, 0x1.fffp
+13L], [-real.max
/ 3, 0x1.fffp
+13L],
4248 /*************************************
4249 * Efficiently calculates x * 2$(SUPERSCRIPT n).
4251 * scalbn handles underflow and overflow in
4252 * the same fashion as the basic arithmetic operators.
4255 * $(TR $(TH x) $(TH scalb(x)))
4256 * $(TR $(TD $(PLUSMNINF)) $(TD $(PLUSMNINF)) )
4257 * $(TR $(TD $(PLUSMN)0.0) $(TD $(PLUSMN)0.0) )
4260 pragma(inline
, true)
4261 real scalbn(real x
, int n
) @safe pure nothrow @nogc { return _scalbn(x
,n
); }
4264 pragma(inline
, true)
4265 double scalbn(double x
, int n
) @safe pure nothrow @nogc { return _scalbn(x
,n
); }
4268 pragma(inline
, true)
4269 float scalbn(float x
, int n
) @safe pure nothrow @nogc { return _scalbn(x
,n
); }
4272 @safe pure nothrow @nogc unittest
4274 assert(scalbn(0x1.2345678abcdefp0L
, 999) == 0x1.2345678abcdefp999L
);
4275 assert(scalbn(-real.infinity
, 5) == -real.infinity
);
4276 assert(scalbn(2.0,10) == 2048.0);
4277 assert(scalbn(2048.0f,-10) == 2.0f);
4280 pragma(inline
, true)
4281 private F
_scalbn(F
)(F x
, int n
)
4283 import std
.math
.traits
: isInfinity
;
4287 // Handle special cases.
4288 if (x
== F(0.0) ||
isInfinity(x
))
4291 return core
.math
.ldexp(x
, n
);
4294 @safe pure nothrow @nogc unittest
4297 static assert(scalbn(0x1.2345678abcdefp0L
, 999) == 0x1.2345678abcdefp999L
);
4298 static assert(scalbn(-real.infinity
, 5) == -real.infinity
);
4299 // Test with large exponent delta n where the result is in bounds but 2.0L ^^ n is not.
4300 enum initialExponent
= real.min_exp
+ 2, resultExponent
= real.max_exp
- 2;
4301 enum int n
= resultExponent
- initialExponent
;
4302 enum real x
= 0x1.2345678abcdefp0L
* (2.0L ^^ initialExponent
);
4303 enum staticResult
= scalbn(x
, n
);
4304 static assert(staticResult
== 0x1.2345678abcdefp0L
* (2.0L ^^ resultExponent
));
4305 assert(scalbn(x
, n
) == staticResult
);