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 @trusted 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 import core
.math
: fabs, sqrt
;
426 import std
.math
.traits
: isInfinity
, isNaN
, signbit
;
428 alias Float
= typeof(return);
430 static real impl(real x
, real y
) @nogc pure nothrow
435 if (isNaN(x
) && y
!= 0.0)
448 if (!signbit(y
) && !signbit(x
))
453 else if (fabs(x
) > 1)
460 else if (fabs(x
) == 1)
476 long i
= cast(long) y
;
509 long i
= cast(long) y
;
538 if ((x
> 0.0 && x
< 1.0) ||
(x
> -1.0 && x
< 0.0))
540 if (x
> 1.0 || x
< -1.0)
545 if ((x
> 0.0 && x
< 1.0) ||
(x
> -1.0 && x
< 0.0))
547 if (x
> 1.0 || x
< -1.0)
560 long i
= cast(long) y
;
577 // Integer power of x.
578 long iy
= cast(long) y
;
579 if (iy
== y
&& fabs(y
) < 32_768.0)
585 // Result is real only if y is an integer
586 // Check for a non-zero fractional part
587 enum maxOdd
= pow(2.0L, real.mant_dig
) - 1.0L;
588 static if (maxOdd
> ulong.max
)
590 // Generic method, for any FP type
591 import std
.math
.rounding
: floor
;
593 return sqrt(x
); // Complex result -- create a NaN
601 // Much faster, if ulong has enough precision
602 const absY
= fabs(y
);
605 const uy
= cast(ulong) absY
;
607 return sqrt(x
); // Complex result -- create a NaN
615 version (INLINE_YL2X
)
617 // If x > 0, x ^^ y == 2 ^^ ( y * log2(x) )
618 // TODO: This is not accurate in practice. A fast and accurate
619 // (though complicated) method is described in:
620 // "An efficient rounding boundary test for pow(x, y)
621 // in double precision", C.Q. Lauter and V. Lefèvre, INRIA (2007).
622 return sign
* exp2( core
.math
.yl2x(x
, y
) );
626 // If x > 0, x ^^ y == 2 ^^ ( y * log2(x) )
627 // TODO: This is not accurate in practice. A fast and accurate
628 // (though complicated) method is described in:
629 // "An efficient rounding boundary test for pow(x, y)
630 // in double precision", C.Q. Lauter and V. Lefèvre, INRIA (2007).
631 Float w
= exp2(y
* log2(x
));
639 @safe pure nothrow @nogc unittest
641 import std
.math
.operations
: isClose
;
643 assert(isClose(pow(2.0, 3.0), 8.0));
644 assert(isClose(pow(1.5, 10.0), 57.6650390625));
647 assert(isClose(pow(9.0, 0.5), 3.0));
649 assert(isClose(pow(1024.0, 0.1), 2.0));
651 assert(isClose(pow(-4.0, 3.0), -64.0));
653 // reciprocal of 4 ^^ 2
654 assert(isClose(pow(4.0, -2.0), 0.0625));
655 // reciprocal of (-2) ^^ 3
656 assert(isClose(pow(-2.0, -3.0), -0.125));
658 assert(isClose(pow(-2.5, 3.0), -15.625));
659 // reciprocal of 2.5 ^^ 3
660 assert(isClose(pow(2.5, -3.0), 0.064));
661 // reciprocal of (-2.5) ^^ 3
662 assert(isClose(pow(-2.5, -3.0), -0.064));
664 // reciprocal of square root of 4
665 assert(isClose(pow(4.0, -0.5), 0.5));
668 assert(isClose(pow(0.0, 0.0), 1.0));
672 @safe pure nothrow @nogc unittest
674 import std
.math
.operations
: isClose
;
676 // the result is a complex number
677 // which cannot be represented as floating point number
678 import std
.math
.traits
: isNaN
;
679 assert(isNaN(pow(-2.5, -1.5)));
681 // use the ^^-operator of std.complex instead
682 import std
.complex
: complex
;
683 auto c1
= complex(-2.5, 0.0);
684 auto c2
= complex(-1.5, 0.0);
685 auto result
= c1 ^^ c2
;
686 // exact result apparently depends on `real` precision => increased tolerance
687 assert(isClose(result
.re
, -4.64705438e-17, 2e-4));
688 assert(isClose(result
.im
, 2.52982e-1, 2e-4));
691 @safe pure nothrow @nogc unittest
693 import std
.math
.traits
: isNaN
;
695 assert(pow(1.5, real.infinity
) == real.infinity
);
696 assert(pow(0.5, real.infinity
) == 0.0);
697 assert(pow(1.5, -real.infinity
) == 0.0);
698 assert(pow(0.5, -real.infinity
) == real.infinity
);
699 assert(pow(real.infinity
, 1.0) == real.infinity
);
700 assert(pow(real.infinity
, -1.0) == 0.0);
701 assert(pow(real.infinity
, real.infinity
) == real.infinity
);
702 assert(pow(-real.infinity
, 1.0) == -real.infinity
);
703 assert(pow(-real.infinity
, 2.0) == real.infinity
);
704 assert(pow(-real.infinity
, -1.0) == -0.0);
705 assert(pow(-real.infinity
, -2.0) == 0.0);
706 assert(isNaN(pow(1.0, real.infinity
)));
707 assert(pow(0.0, -1.0) == real.infinity
);
708 assert(pow(real.nan
, 0.0) == 1.0);
709 assert(isNaN(pow(real.nan
, 3.0)));
710 assert(isNaN(pow(3.0, real.nan
)));
713 @safe @nogc nothrow unittest
715 import std
.math
.operations
: isClose
;
717 assert(isClose(pow(2.0L, 10.0L), 1024, 1e-18));
720 @safe pure nothrow @nogc unittest
722 import std
.math
.operations
: isClose
;
723 import std
.math
.traits
: isIdentical
, isNaN
;
724 import std
.math
.constants
: PI
;
726 // Test all the special values. These unittests can be run on Windows
727 // by temporarily changing the version (linux) to version (all).
728 immutable float zero
= 0;
729 immutable real one
= 1;
730 immutable double two
= 2;
731 immutable float three
= 3;
732 immutable float fnan
= float.nan
;
733 immutable double dnan
= double.nan
;
734 immutable real rnan
= real.nan
;
735 immutable dinf
= double.infinity
;
736 immutable rninf
= -real.infinity
;
738 assert(pow(fnan
, zero
) == 1);
739 assert(pow(dnan
, zero
) == 1);
740 assert(pow(rnan
, zero
) == 1);
742 assert(pow(two
, dinf
) == double.infinity
);
743 assert(isIdentical(pow(0.2f, dinf
), +0.0));
744 assert(pow(0.99999999L, rninf
) == real.infinity
);
745 assert(isIdentical(pow(1.000000001, rninf
), +0.0));
746 assert(pow(dinf
, 0.001) == dinf
);
747 assert(isIdentical(pow(dinf
, -0.001), +0.0));
748 assert(pow(rninf
, 3.0L) == rninf
);
749 assert(pow(rninf
, 2.0L) == real.infinity
);
750 assert(isIdentical(pow(rninf
, -3.0), -0.0));
751 assert(isIdentical(pow(rninf
, -2.0), +0.0));
753 // @@@BUG@@@ somewhere
754 version (OSX
) {} else assert(isNaN(pow(one
, dinf
)));
755 version (OSX
) {} else assert(isNaN(pow(-one
, dinf
)));
756 assert(isNaN(pow(-0.2, PI
)));
757 // boundary cases. Note that epsilon == 2^^-n for some n,
758 // so 1/epsilon == 2^^n is always even.
759 assert(pow(-1.0L, 1/real.epsilon
- 1.0L) == -1.0L);
760 assert(pow(-1.0L, 1/real.epsilon
) == 1.0L);
761 assert(isNaN(pow(-1.0L, 1/real.epsilon
-0.5L)));
762 assert(isNaN(pow(-1.0L, -1/real.epsilon
+0.5L)));
764 assert(pow(0.0, -3.0) == double.infinity
);
765 assert(pow(-0.0, -3.0) == -double.infinity
);
766 assert(pow(0.0, -PI
) == double.infinity
);
767 assert(pow(-0.0, -PI
) == double.infinity
);
768 assert(isIdentical(pow(0.0, 5.0), 0.0));
769 assert(isIdentical(pow(-0.0, 5.0), -0.0));
770 assert(isIdentical(pow(0.0, 6.0), 0.0));
771 assert(isIdentical(pow(-0.0, 6.0), 0.0));
773 // https://issues.dlang.org/show_bug.cgi?id=14786 fixed
774 immutable real maxOdd
= pow(2.0L, real.mant_dig
) - 1.0L;
775 assert(pow(-1.0L, maxOdd
) == -1.0L);
776 assert(pow(-1.0L, -maxOdd
) == -1.0L);
777 assert(pow(-1.0L, maxOdd
+ 1.0L) == 1.0L);
778 assert(pow(-1.0L, -maxOdd
+ 1.0L) == 1.0L);
779 assert(pow(-1.0L, maxOdd
- 1.0L) == 1.0L);
780 assert(pow(-1.0L, -maxOdd
- 1.0L) == 1.0L);
782 // Now, actual numbers.
783 assert(isClose(pow(two
, three
), 8.0));
784 assert(isClose(pow(two
, -2.5), 0.1767766953));
786 // Test integer to float power.
787 immutable uint twoI
= 2;
788 assert(isClose(pow(twoI
, three
), 8.0));
791 // https://issues.dlang.org/show_bug.cgi?id=20508
792 @safe pure nothrow @nogc unittest
794 import std
.math
.traits
: isNaN
;
796 assert(isNaN(pow(-double.infinity
, 0.5)));
798 assert(isNaN(pow(-real.infinity
, real.infinity
)));
799 assert(isNaN(pow(-real.infinity
, -real.infinity
)));
800 assert(isNaN(pow(-real.infinity
, 1.234)));
801 assert(isNaN(pow(-real.infinity
, -0.751)));
802 assert(pow(-real.infinity
, 0.0) == 1.0);
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
: floatTraits
, RealFormat
;
1006 import std
.math
.traits
: isNaN
;
1007 import std
.math
.rounding
: floor
;
1008 import std
.math
.algebraic
: poly
;
1009 import std
.math
.constants
: LOG2E
;
1011 alias F
= floatTraits
!T
;
1012 static if (F
.realFormat
== RealFormat
.ieeeSingle
)
1014 static immutable T
[6] P
= [
1023 enum T C1
= 0.693359375;
1024 enum T C2
= -2.12194440e-4;
1026 // Overflow and Underflow limits.
1027 enum T OF
= 88.72283905206835;
1028 enum T UF
= -103.278929903431851103; // ln(2^-149)
1030 else static if (F
.realFormat
== RealFormat
.ieeeDouble
)
1032 // Coefficients for exp(x)
1033 static immutable T
[3] P
= [
1034 9.99999999999999999910E-1L,
1035 3.02994407707441961300E-2L,
1036 1.26177193074810590878E-4L,
1038 static immutable T
[4] Q
= [
1039 2.00000000000000000009E0L
,
1040 2.27265548208155028766E-1L,
1041 2.52448340349684104192E-3L,
1042 3.00198505138664455042E-6L,
1046 enum T C1
= 6.93145751953125E-1;
1047 enum T C2
= 1.42860682030941723212E-6;
1049 // Overflow and Underflow limits.
1050 enum T OF
= 7.09782712893383996732E2
; // ln((1-2^-53) * 2^1024)
1051 enum T UF
= -7.451332191019412076235E2
; // ln(2^-1075)
1053 else static if (F
.realFormat
== RealFormat
.ieeeExtended ||
1054 F
.realFormat
== RealFormat
.ieeeExtended53
)
1056 // Coefficients for exp(x)
1057 static immutable T
[3] P
= [
1058 9.9999999999999999991025E-1L,
1059 3.0299440770744196129956E-2L,
1060 1.2617719307481059087798E-4L,
1062 static immutable T
[4] Q
= [
1063 2.0000000000000000000897E0L
,
1064 2.2726554820815502876593E-1L,
1065 2.5244834034968410419224E-3L,
1066 3.0019850513866445504159E-6L,
1070 enum T C1
= 6.9314575195312500000000E-1L;
1071 enum T C2
= 1.4286068203094172321215E-6L;
1073 // Overflow and Underflow limits.
1074 enum T OF
= 1.1356523406294143949492E4L
; // ln((1-2^-64) * 2^16384)
1075 enum T UF
= -1.13994985314888605586758E4L
; // ln(2^-16446)
1077 else static if (F
.realFormat
== RealFormat
.ieeeQuadruple
)
1079 // Coefficients for exp(x) - 1
1080 static immutable T
[5] P
= [
1081 9.999999999999999999999999999999999998502E-1L,
1082 3.508710990737834361215404761139478627390E-2L,
1083 2.708775201978218837374512615596512792224E-4L,
1084 6.141506007208645008909088812338454698548E-7L,
1085 3.279723985560247033712687707263393506266E-10L
1087 static immutable T
[6] Q
= [
1088 2.000000000000000000000000000000000000150E0
,
1089 2.368408864814233538909747618894558968880E-1L,
1090 3.611828913847589925056132680618007270344E-3L,
1091 1.504792651814944826817779302637284053660E-5L,
1092 1.771372078166251484503904874657985291164E-8L,
1093 2.980756652081995192255342779918052538681E-12L
1097 enum T C1
= 6.93145751953125E-1L;
1098 enum T C2
= 1.428606820309417232121458176568075500134E-6L;
1100 // Overflow and Underflow limits.
1101 enum T OF
= 1.135583025911358400418251384584930671458833e4L
;
1102 enum T UF
= -1.143276959615573793352782661133116431383730e4L
;
1105 static assert(0, "Not implemented for this architecture");
1111 return real.infinity
;
1115 // Express: e^^x = e^^g * 2^^n
1116 // = e^^g * e^^(n * LOG2E)
1117 // = e^^(g + n * LOG2E)
1118 T xx
= floor((cast(T
) LOG2E
) * x
+ cast(T
) 0.5);
1119 const int n
= cast(int) xx
;
1123 static if (F
.realFormat
== RealFormat
.ieeeSingle
)
1126 x
= poly(x
, P
) * xx
+ x
+ 1.0f;
1130 // Rational approximation for exponential of the fractional part:
1131 // e^^x = 1 + 2x P(x^^2) / (Q(x^^2) - P(x^^2))
1133 const T px
= x
* poly(xx
, P
);
1134 x
= px
/ (poly(xx
, Q
) - px
);
1135 x
= (cast(T
) 1.0) + (cast(T
) 2.0) * x
;
1138 // Scale by power of 2.
1139 x
= core
.math
.ldexp(x
, n
);
1144 @safe @nogc nothrow unittest
1146 import std
.math
: floatTraits
, RealFormat
;
1147 import std
.math
.operations
: NaN
, feqrel
, isClose
;
1148 import std
.math
.constants
: E
;
1149 import std
.math
.traits
: isIdentical
;
1150 import std
.math
.algebraic
: abs
;
1152 version (IeeeFlagsSupport
) import std
.math
.hardware
: IeeeFlags
, resetIeeeFlags
, ieeeFlags
;
1153 version (FloatingPointControlSupport
)
1155 import std
.math
.hardware
: FloatingPointControl
;
1157 FloatingPointControl ctrl
;
1158 if (FloatingPointControl
.hasExceptionTraps
)
1159 ctrl
.disableExceptions(FloatingPointControl
.allExceptions
);
1160 ctrl
.rounding
= FloatingPointControl
.roundToNearest
;
1163 static void testExp(T
)()
1165 enum realFormat
= floatTraits
!T
.realFormat
;
1166 static if (realFormat
== RealFormat
.ieeeQuadruple
)
1168 static immutable T
[2][] exptestpoints
=
1171 [ 0.5L, 0x1.a61298e1e069bc972dfefab6df34p
+0L ],
1173 [ 0x1.6p
+13L, 0x1.6e509d45728655cdb4840542acb5p
+16250L ], // near overflow
1174 [ 0x1.7p
+13L, T
.infinity
], // close overflow
1175 [ 0x1p
+80L, T
.infinity
], // far overflow
1176 [ T
.infinity
, T
.infinity
],
1177 [-0x1.18p
+13L, 0x1.5e4bf54b4807034ea97fef0059a6p
-12927L ], // near underflow
1178 [-0x1.625p
+13L, 0x1.a6bd68a39d11fec3a250cd97f524p
-16358L ], // ditto
1179 [-0x1.62dafp
+13L, 0x0.cb629e9813b80ed4d639e875be6cp
-16382L ], // near underflow - subnormal
1180 [-0x1.6549p
+13L, 0x0.0000000000000000000000000001p
-16382L ], // ditto
1181 [-0x1.655p
+13L, 0 ], // close underflow
1182 [-0x1p
+30L, 0 ], // far underflow
1185 else static if (realFormat
== RealFormat
.ieeeExtended ||
1186 realFormat
== RealFormat
.ieeeExtended53
)
1188 static immutable T
[2][] exptestpoints
=
1191 [ 0.5L, 0x1.a61298e1e069bc97p
+0L ],
1193 [ 0x1.1p
+13L, 0x1.29aeffefc8ec645p
+12557L ], // near overflow
1194 [ 0x1.7p
+13L, T
.infinity
], // close overflow
1195 [ 0x1p
+80L, T
.infinity
], // far overflow
1196 [ T
.infinity
, T
.infinity
],
1197 [-0x1.18p
+13L, 0x1.5e4bf54b4806db9p
-12927L ], // near underflow
1198 [-0x1.625p
+13L, 0x1.a6bd68a39d11f35cp
-16358L ], // ditto
1199 [-0x1.62dafp
+13L, 0x1.96c53d30277021dp
-16383L ], // near underflow - subnormal
1200 [-0x1.643p
+13L, 0x1p
-16444L ], // ditto
1201 [-0x1.645p
+13L, 0 ], // close underflow
1202 [-0x1p
+30L, 0 ], // far underflow
1205 else static if (realFormat
== RealFormat
.ieeeDouble
)
1207 static immutable T
[2][] exptestpoints
=
1210 [ 0.5L, 0x1.a61298e1e069cp
+0L ],
1212 [ 0x1.6p
+9L, 0x1.93bf4ec
282efbp
+1015L ], // near overflow
1213 [ 0x1.7p
+9L, T
.infinity
], // close overflow
1214 [ 0x1p
+80L, T
.infinity
], // far overflow
1215 [ T
.infinity
, T
.infinity
],
1216 [-0x1.6p
+9L, 0x1.44a3824e5285fp
-1016L ], // near underflow
1217 [-0x1.64p
+9L, 0x0.06f84920bb2d4p
-1022L ], // near underflow - subnormal
1218 [-0x1.743p
+9L, 0x0.0000000000001p
-1022L ], // ditto
1219 [-0x1.8p
+9L, 0 ], // close underflow
1220 [-0x1p
+30L, 0 ], // far underflow
1223 else static if (realFormat
== RealFormat
.ieeeSingle
)
1225 static immutable T
[2][] exptestpoints
=
1228 [ 0.5L, 0x1.a61299p
+0L ],
1230 [ 0x1.62p
+6L, 0x1.99b988p
+127L ], // near overflow
1231 [ 0x1.7p
+6L, T
.infinity
], // close overflow
1232 [ 0x1p
+80L, T
.infinity
], // far overflow
1233 [ T
.infinity
, T
.infinity
],
1234 [-0x1.5cp
+6L, 0x1.666d0ep
-126L ], // near underflow
1235 [-0x1.7p
+6L, 0x0.026a42p
-126L ], // near underflow - subnormal
1236 [-0x1.9cp
+6L, 0x0.000002p
-126L ], // ditto
1237 [-0x1.ap
+6L, 0 ], // close underflow
1238 [-0x1p
+30L, 0 ], // far underflow
1242 static assert(0, "No exp() tests for real type!");
1244 const minEqualMantissaBits
= T
.mant_dig
- 13;
1246 version (IeeeFlagsSupport
) IeeeFlags f
;
1247 foreach (ref pair
; exptestpoints
)
1249 version (IeeeFlagsSupport
) resetIeeeFlags();
1251 //printf("exp(%La) = %La, should be %La\n", cast(real) pair[0], cast(real) x, cast(real) pair[1]);
1252 assert(feqrel(x
, pair
[1]) >= minEqualMantissaBits
);
1255 // Ideally, exp(0) would not set the inexact flag.
1256 // Unfortunately, fldl2e sets it!
1257 // So it's not realistic to avoid setting it.
1258 assert(exp(cast(T
) 0.0) == 1.0);
1260 // NaN propagation. Doesn't set flags, bcos was already NaN.
1261 version (IeeeFlagsSupport
)
1266 assert(isIdentical(abs(x
), T
.nan
));
1267 assert(f
.flags
== 0);
1272 assert(isIdentical(abs(x
), T
.nan
));
1273 assert(f
.flags
== 0);
1278 assert(isIdentical(abs(x
), T
.nan
));
1281 assert(isIdentical(abs(x
), T
.nan
));
1284 x
= exp(NaN(0x123));
1285 assert(isIdentical(x
, NaN(0x123)));
1288 import std
.meta
: AliasSeq
;
1289 foreach (T
; AliasSeq
!(real, double, float))
1292 // High resolution test (verified against GNU MPFR/Mathematica).
1293 assert(exp(0.5L) == 0x1.A612_98E1_E069_BC97_2DFE_FAB6_DF34p
+0L);
1295 assert(isClose(exp(3.0L), E
* E
* E
, real.sizeof
> double.sizeof ?
1e-15 : 1e-14));
1299 * Calculates the value of the natural logarithm base (e)
1300 * raised to the power of x, minus 1.
1302 * For very small x, expm1(x) is more accurate
1306 * $(TR $(TH x) $(TH e$(SUPERSCRIPT x)-1) )
1307 * $(TR $(TD $(PLUSMN)0.0) $(TD $(PLUSMN)0.0) )
1308 * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) )
1309 * $(TR $(TD -$(INFIN)) $(TD -1.0) )
1310 * $(TR $(TD $(NAN)) $(TD $(NAN)) )
1313 pragma(inline
, true)
1314 real expm1(real x
) @trusted pure nothrow @nogc // TODO: @safe
1316 version (InlineAsm_X87
)
1321 return expm1Impl(x
);
1325 pragma(inline
, true)
1326 double expm1(double x
) @safe pure nothrow @nogc
1328 return __ctfe ?
cast(double) expm1(cast(real) x
) : expm1Impl(x
);
1332 pragma(inline
, true)
1333 float expm1(float x
) @safe pure nothrow @nogc
1335 // no single-precision version in Cephes => use double precision
1336 return __ctfe ?
cast(float) expm1(cast(real) x
) : cast(float) expm1Impl(cast(double) x
);
1342 import std
.math
.traits
: isIdentical
;
1343 import std
.math
.operations
: feqrel
;
1345 assert(isIdentical(expm1(0.0), 0.0));
1346 assert(expm1(1.0).feqrel(1.71828) > 16);
1347 assert(expm1(2.0).feqrel(6.3890) > 16);
1350 version (InlineAsm_X87
)
1351 private real expm1Asm(real x
) @trusted pure nothrow @nogc
1355 enum PARAMSIZE
= (real.sizeof
+3)&(0xFFFF_FFFC
); // always a multiple of 4
1356 asm pure nothrow @nogc
1358 /* expm1() for x87 80-bit reals, IEEE754-2008 conformant.
1359 * Author: Don Clugston.
1361 * expm1(x) = 2^^(rndint(y))* 2^^(y-rndint(y)) - 1 where y = LN2*x.
1362 * = 2rndy * 2ym1 + 2rndy - 1, where 2rndy = 2^^(rndint(y))
1363 * and 2ym1 = (2^^(y-rndint(y))-1).
1364 * If 2rndy < 0.5*real.epsilon, result is -1.
1365 * Implementation is otherwise the same as for exp2()
1368 fld real ptr
[ESP
+4] ; // x
1369 mov AX
, [ESP
+4+8]; // AX = exponent and sign
1370 sub ESP
, 12+8; // Create scratch space on the stack
1371 // [ESP,ESP+2] = scratchint
1372 // [ESP+4..+6, +8..+10, +10] = scratchreal
1373 // set scratchreal mantissa = 1.0
1374 mov dword ptr
[ESP
+8], 0;
1375 mov dword ptr
[ESP
+8+4], 0x80000000;
1376 and AX
, 0x7FFF; // drop sign bit
1377 cmp AX
, 0x401D; // avoid InvalidException in fist
1380 fmulp ST(1), ST
; // y = x*log2(e)
1381 fist dword ptr
[ESP
]; // scratchint = rndint(y)
1382 fisub dword ptr
[ESP
]; // y - rndint(y)
1383 // and now set scratchreal exponent
1386 jle short L_largenegative
;
1388 jge short L_largepositive
;
1390 f2xm1; // 2ym1 = 2^^(y-rndint(y)) -1
1391 fld real ptr
[ESP
+8] ; // 2rndy = 2^^rndint(y)
1392 fmul ST(1), ST
; // ST=2rndy, ST(1)=2rndy*2ym1
1394 fsubp ST(1), ST
; // ST = 2rndy-1, ST(1) = 2rndy * 2ym1 - 1
1395 faddp ST(1), ST
; // ST = 2rndy * 2ym1 + 2rndy - 1
1399 L_extreme
: // Extreme exponent. X is very large positive, very
1400 // large negative, infinity, or NaN.
1403 test AX
, 0x0400; // NaN_or_zero, but we already know x != 0
1404 jz L_was_nan
; // if x is NaN, returns x
1406 jnz L_largenegative
;
1408 // Set scratchreal = real.max.
1409 // squaring it will create infinity, and set overflow flag.
1410 mov word ptr
[ESP
+8+8], 0x7FFE;
1412 fld real ptr
[ESP
+8]; // load scratchreal
1413 fmul ST(0), ST
; // square it, to create havoc!
1420 fchs; // return -1. Underflow flag is not set.
1425 else version (X86_64
)
1427 asm pure nothrow @nogc
1433 asm pure nothrow @nogc
1435 fld real ptr
[RCX
]; // x
1436 mov AX
,[RCX
+8]; // AX = exponent and sign
1441 asm pure nothrow @nogc
1443 fld real ptr
[RSP
+8]; // x
1444 mov AX
,[RSP
+8+8]; // AX = exponent and sign
1447 asm pure nothrow @nogc
1449 /* expm1() for x87 80-bit reals, IEEE754-2008 conformant.
1450 * Author: Don Clugston.
1452 * expm1(x) = 2^(rndint(y))* 2^(y-rndint(y)) - 1 where y = LN2*x.
1453 * = 2rndy * 2ym1 + 2rndy - 1, where 2rndy = 2^(rndint(y))
1454 * and 2ym1 = (2^(y-rndint(y))-1).
1455 * If 2rndy < 0.5*real.epsilon, result is -1.
1456 * Implementation is otherwise the same as for exp2()
1458 sub RSP
, 24; // Create scratch space on the stack
1459 // [RSP,RSP+2] = scratchint
1460 // [RSP+4..+6, +8..+10, +10] = scratchreal
1461 // set scratchreal mantissa = 1.0
1462 mov dword ptr
[RSP
+8], 0;
1463 mov dword ptr
[RSP
+8+4], 0x80000000;
1464 and AX
, 0x7FFF; // drop sign bit
1465 cmp AX
, 0x401D; // avoid InvalidException in fist
1468 fmul ; // y = x*log2(e)
1469 fist dword ptr
[RSP
]; // scratchint = rndint(y)
1470 fisub dword ptr
[RSP
]; // y - rndint(y)
1471 // and now set scratchreal exponent
1474 jle short L_largenegative
;
1476 jge short L_largepositive
;
1478 f2xm1; // 2^(y-rndint(y)) -1
1479 fld real ptr
[RSP
+8] ; // 2^rndint(y)
1487 L_extreme
: // Extreme exponent. X is very large positive, very
1488 // large negative, infinity, or NaN.
1491 test AX
, 0x0400; // NaN_or_zero, but we already know x != 0
1492 jz L_was_nan
; // if x is NaN, returns x
1494 jnz L_largenegative
;
1496 // Set scratchreal = real.max.
1497 // squaring it will create infinity, and set overflow flag.
1498 mov word ptr
[RSP
+8+8], 0x7FFE;
1500 fld real ptr
[RSP
+8]; // load scratchreal
1501 fmul ST(0), ST
; // square it, to create havoc!
1509 fchs; // return -1. Underflow flag is not set.
1518 private T
expm1Impl(T
)(T x
) @safe pure nothrow @nogc
1520 import std
.math
: floatTraits
, RealFormat
;
1521 import std
.math
.rounding
: floor
;
1522 import std
.math
.algebraic
: poly
;
1523 import std
.math
.constants
: LN2
;
1525 // Coefficients for exp(x) - 1 and overflow/underflow limits.
1526 enum realFormat
= floatTraits
!T
.realFormat
;
1527 static if (realFormat
== RealFormat
.ieeeQuadruple
)
1529 static immutable T
[8] P
= [
1530 2.943520915569954073888921213330863757240E8L
,
1531 -5.722847283900608941516165725053359168840E7L
,
1532 8.944630806357575461578107295909719817253E6L
,
1533 -7.212432713558031519943281748462837065308E5L
,
1534 4.578962475841642634225390068461943438441E4L
,
1535 -1.716772506388927649032068540558788106762E3L
,
1536 4.401308817383362136048032038528753151144E1L
,
1537 -4.888737542888633647784737721812546636240E-1L
1540 static immutable T
[9] Q
= [
1541 1.766112549341972444333352727998584753865E9L
,
1542 -7.848989743695296475743081255027098295771E8L
,
1543 1.615869009634292424463780387327037251069E8L
,
1544 -2.019684072836541751428967854947019415698E7L
,
1545 1.682912729190313538934190635536631941751E6L
,
1546 -9.615511549171441430850103489315371768998E4L
,
1547 3.697714952261803935521187272204485251835E3L
,
1548 -8.802340681794263968892934703309274564037E1L
,
1552 enum T OF
= 1.1356523406294143949491931077970764891253E4L
;
1553 enum T UF
= -1.143276959615573793352782661133116431383730e4L
;
1555 else static if (realFormat
== RealFormat
.ieeeExtended
)
1557 static immutable T
[5] P
= [
1558 -1.586135578666346600772998894928250240826E4L
,
1559 2.642771505685952966904660652518429479531E3L
,
1560 -3.423199068835684263987132888286791620673E2L
,
1561 1.800826371455042224581246202420972737840E1L
,
1562 -5.238523121205561042771939008061958820811E-1L,
1564 static immutable T
[6] Q
= [
1565 -9.516813471998079611319047060563358064497E4L
,
1566 3.964866271411091674556850458227710004570E4L
,
1567 -7.207678383830091850230366618190187434796E3L
,
1568 7.206038318724600171970199625081491823079E2L
,
1569 -4.002027679107076077238836622982900945173E1L
,
1573 enum T OF
= 1.1356523406294143949492E4L
;
1574 enum T UF
= -4.5054566736396445112120088E1L
;
1576 else static if (realFormat
== RealFormat
.ieeeDouble
)
1578 static immutable T
[3] P
= [
1579 9.9999999999999999991025E-1,
1580 3.0299440770744196129956E-2,
1581 1.2617719307481059087798E-4,
1583 static immutable T
[4] Q
= [
1584 2.0000000000000000000897E0
,
1585 2.2726554820815502876593E-1,
1586 2.5244834034968410419224E-3,
1587 3.0019850513866445504159E-6,
1591 static assert(0, "no coefficients for expm1()");
1593 static if (realFormat
== RealFormat
.ieeeDouble
) // special case for double precision
1595 if (x
< -0.5 || x
> 0.5)
1596 return exp(x
) - 1.0;
1601 x
= x
* poly(xx
, P
);
1602 x
= x
/ (poly(xx
, Q
) - x
);
1608 enum T C1
= 6.9314575195312500000000E-1L;
1609 enum T C2
= 1.428606820309417232121458176568075500134E-6L;
1613 return real.infinity
;
1614 if (x
== cast(T
) 0.0)
1619 // Express x = LN2 (n + remainder), remainder not exceeding 1/2.
1620 int n
= cast(int) floor((cast(T
) 0.5) + x
/ cast(T
) LN2
);
1624 // Rational approximation:
1625 // exp(x) - 1 = x + 0.5 x^^2 + x^^3 P(x) / Q(x)
1626 T px
= x
* poly(x
, P
);
1629 qx
= x
+ ((cast(T
) 0.5) * xx
+ xx
* px
/ qx
);
1631 // We have qx = exp(remainder LN2) - 1, so:
1632 // exp(x) - 1 = 2^^n (qx + 1) - 1 = 2^^n qx + 2^^n - 1.
1633 px
= core
.math
.ldexp(cast(T
) 1.0, n
);
1634 x
= px
* qx
+ (px
- cast(T
) 1.0);
1640 @safe @nogc nothrow unittest
1642 import std
.math
.traits
: isNaN
;
1643 import std
.math
.operations
: isClose
, CommonDefaultFor
;
1645 static void testExpm1(T
)()
1648 assert(isNaN(expm1(cast(T
) T
.nan
)));
1650 static immutable T
[] xs
= [ -2, -0.75, -0.3, 0.0, 0.1, 0.2, 0.5, 1.0 ];
1653 const T e
= expm1(x
);
1654 const T r
= exp(x
) - 1;
1656 //printf("expm1(%Lg) = %Lg, should approximately be %Lg\n", cast(real) x, cast(real) e, cast(real) r);
1657 assert(isClose(r
, e
, CommonDefaultFor
!(T
,T
), CommonDefaultFor
!(T
,T
)));
1661 import std
.meta
: AliasSeq
;
1662 foreach (T
; AliasSeq
!(real, double))
1667 * Calculates 2$(SUPERSCRIPT x).
1670 * $(TR $(TH x) $(TH exp2(x)) )
1671 * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) )
1672 * $(TR $(TD -$(INFIN)) $(TD +0.0) )
1673 * $(TR $(TD $(NAN)) $(TD $(NAN)) )
1676 pragma(inline
, true)
1677 real exp2(real x
) @nogc @trusted pure nothrow // TODO: @safe
1679 version (InlineAsm_X87
)
1688 pragma(inline
, true)
1689 double exp2(double x
) @nogc @safe pure nothrow { return __ctfe ?
cast(double) exp2(cast(real) x
) : exp2Impl(x
); }
1692 pragma(inline
, true)
1693 float exp2(float x
) @nogc @safe pure nothrow { return __ctfe ?
cast(float) exp2(cast(real) x
) : exp2Impl(x
); }
1698 import std
.math
.traits
: isIdentical
;
1699 import std
.math
.operations
: feqrel
;
1701 assert(isIdentical(exp2(0.0), 1.0));
1702 assert(exp2(2.0).feqrel(4.0) > 16);
1703 assert(exp2(8.0).feqrel(256.0) > 16);
1708 version (CRuntime_Microsoft
) {} else // aexp2/exp2f/exp2l not implemented
1710 assert( core
.stdc
.math
.exp2f(0.0f) == 1 );
1711 assert( core
.stdc
.math
.exp2 (0.0) == 1 );
1712 assert( core
.stdc
.math
.exp2l(0.0L) == 1 );
1716 version (InlineAsm_X87
)
1717 private real exp2Asm(real x
) @nogc @trusted pure nothrow
1721 enum PARAMSIZE
= (real.sizeof
+3)&(0xFFFF_FFFC
); // always a multiple of 4
1723 asm pure nothrow @nogc
1725 /* exp2() for x87 80-bit reals, IEEE754-2008 conformant.
1726 * Author: Don Clugston.
1728 * exp2(x) = 2^^(rndint(x))* 2^^(y-rndint(x))
1729 * The trick for high performance is to avoid the fscale(28cycles on core2),
1730 * frndint(19 cycles), leaving f2xm1(19 cycles) as the only slow instruction.
1732 * We can do frndint by using fist. BUT we can't use it for huge numbers,
1733 * because it will set the Invalid Operation flag if overflow or NaN occurs.
1734 * Fortunately, whenever this happens the result would be zero or infinity.
1736 * We can perform fscale by directly poking into the exponent. BUT this doesn't
1737 * work for the (very rare) cases where the result is subnormal. So we fall back
1738 * to the slow method in that case.
1741 fld real ptr
[ESP
+4] ; // x
1742 mov AX
, [ESP
+4+8]; // AX = exponent and sign
1743 sub ESP
, 12+8; // Create scratch space on the stack
1744 // [ESP,ESP+2] = scratchint
1745 // [ESP+4..+6, +8..+10, +10] = scratchreal
1746 // set scratchreal mantissa = 1.0
1747 mov dword ptr
[ESP
+8], 0;
1748 mov dword ptr
[ESP
+8+4], 0x80000000;
1749 and AX
, 0x7FFF; // drop sign bit
1750 cmp AX
, 0x401D; // avoid InvalidException in fist
1752 fist dword ptr
[ESP
]; // scratchint = rndint(x)
1753 fisub dword ptr
[ESP
]; // x - rndint(x)
1754 // and now set scratchreal exponent
1757 jle short L_subnormal
;
1759 jge short L_overflow
;
1764 faddp ST(1), ST
; // 2^^(x-rndint(x))
1765 fld real ptr
[ESP
+8] ; // 2^^rndint(x)
1771 // Result will be subnormal.
1772 // In this rare case, the simple poking method doesn't work.
1773 // The speed doesn't matter, so use the slow fscale method.
1774 fild dword ptr
[ESP
]; // scratchint
1777 fstp real ptr
[ESP
+8]; // scratchreal = 2^^scratchint
1778 fstp ST(0); // drop scratchint
1781 L_extreme
: // Extreme exponent. X is very large positive, very
1782 // large negative, infinity, or NaN.
1785 test AX
, 0x0400; // NaN_or_zero, but we already know x != 0
1786 jz L_was_nan
; // if x is NaN, returns x
1787 // set scratchreal = real.min_normal
1788 // squaring it will return 0, setting underflow flag
1789 mov word ptr
[ESP
+8+8], 1;
1791 jnz L_waslargenegative
;
1793 // Set scratchreal = real.max.
1794 // squaring it will create infinity, and set overflow flag.
1795 mov word ptr
[ESP
+8+8], 0x7FFE;
1798 fld real ptr
[ESP
+8]; // load scratchreal
1799 fmul ST(0), ST
; // square it, to create havoc!
1805 else version (X86_64
)
1807 asm pure nothrow @nogc
1813 asm pure nothrow @nogc
1815 fld real ptr
[RCX
]; // x
1816 mov AX
,[RCX
+8]; // AX = exponent and sign
1821 asm pure nothrow @nogc
1823 fld real ptr
[RSP
+8]; // x
1824 mov AX
,[RSP
+8+8]; // AX = exponent and sign
1827 asm pure nothrow @nogc
1829 /* exp2() for x87 80-bit reals, IEEE754-2008 conformant.
1830 * Author: Don Clugston.
1832 * exp2(x) = 2^(rndint(x))* 2^(y-rndint(x))
1833 * The trick for high performance is to avoid the fscale(28cycles on core2),
1834 * frndint(19 cycles), leaving f2xm1(19 cycles) as the only slow instruction.
1836 * We can do frndint by using fist. BUT we can't use it for huge numbers,
1837 * because it will set the Invalid Operation flag is overflow or NaN occurs.
1838 * Fortunately, whenever this happens the result would be zero or infinity.
1840 * We can perform fscale by directly poking into the exponent. BUT this doesn't
1841 * work for the (very rare) cases where the result is subnormal. So we fall back
1842 * to the slow method in that case.
1844 sub RSP
, 24; // Create scratch space on the stack
1845 // [RSP,RSP+2] = scratchint
1846 // [RSP+4..+6, +8..+10, +10] = scratchreal
1847 // set scratchreal mantissa = 1.0
1848 mov dword ptr
[RSP
+8], 0;
1849 mov dword ptr
[RSP
+8+4], 0x80000000;
1850 and AX
, 0x7FFF; // drop sign bit
1851 cmp AX
, 0x401D; // avoid InvalidException in fist
1853 fist dword ptr
[RSP
]; // scratchint = rndint(x)
1854 fisub dword ptr
[RSP
]; // x - rndint(x)
1855 // and now set scratchreal exponent
1858 jle short L_subnormal
;
1860 jge short L_overflow
;
1865 fadd; // 2^(x-rndint(x))
1866 fld real ptr
[RSP
+8] ; // 2^rndint(x)
1872 // Result will be subnormal.
1873 // In this rare case, the simple poking method doesn't work.
1874 // The speed doesn't matter, so use the slow fscale method.
1875 fild dword ptr
[RSP
]; // scratchint
1878 fstp real ptr
[RSP
+8]; // scratchreal = 2^scratchint
1879 fstp ST(0); // drop scratchint
1882 L_extreme
: // Extreme exponent. X is very large positive, very
1883 // large negative, infinity, or NaN.
1886 test AX
, 0x0400; // NaN_or_zero, but we already know x != 0
1887 jz L_was_nan
; // if x is NaN, returns x
1888 // set scratchreal = real.min
1889 // squaring it will return 0, setting underflow flag
1890 mov word ptr
[RSP
+8+8], 1;
1892 jnz L_waslargenegative
;
1894 // Set scratchreal = real.max.
1895 // squaring it will create infinity, and set overflow flag.
1896 mov word ptr
[RSP
+8+8], 0x7FFE;
1899 fld real ptr
[RSP
+8]; // load scratchreal
1900 fmul ST(0), ST
; // square it, to create havoc!
1910 private T
exp2Impl(T
)(T x
) @nogc @safe pure nothrow
1912 import std
.math
: floatTraits
, RealFormat
;
1913 import std
.math
.traits
: isNaN
;
1914 import std
.math
.rounding
: floor
;
1915 import std
.math
.algebraic
: poly
;
1917 // Coefficients for exp2(x)
1918 enum realFormat
= floatTraits
!T
.realFormat
;
1919 static if (realFormat
== RealFormat
.ieeeQuadruple
)
1921 static immutable T
[5] P
= [
1922 9.079594442980146270952372234833529694788E12L
,
1923 1.530625323728429161131811299626419117557E11L
,
1924 5.677513871931844661829755443994214173883E8L
,
1925 6.185032670011643762127954396427045467506E5L
,
1926 1.587171580015525194694938306936721666031E2L
1929 static immutable T
[6] Q
= [
1930 2.619817175234089411411070339065679229869E13L
,
1931 1.490560994263653042761789432690793026977E12L
,
1932 1.092141473886177435056423606755843616331E10L
,
1933 2.186249607051644894762167991800811827835E7L
,
1934 1.236602014442099053716561665053645270207E4L
,
1938 else static if (realFormat
== RealFormat
.ieeeExtended
)
1940 static immutable T
[3] P
= [
1941 2.0803843631901852422887E6L
,
1942 3.0286971917562792508623E4L
,
1943 6.0614853552242266094567E1L
,
1945 static immutable T
[4] Q
= [
1946 6.0027204078348487957118E6L
,
1947 3.2772515434906797273099E5L
,
1948 1.7492876999891839021063E3L
,
1949 1.0000000000000000000000E0L
,
1952 else static if (realFormat
== RealFormat
.ieeeDouble
)
1954 static immutable T
[3] P
= [
1955 1.51390680115615096133E3L
,
1956 2.02020656693165307700E1L
,
1957 2.30933477057345225087E-2L,
1959 static immutable T
[3] Q
= [
1960 4.36821166879210612817E3L
,
1961 2.33184211722314911771E2L
,
1962 1.00000000000000000000E0L
,
1965 else static if (realFormat
== RealFormat
.ieeeSingle
)
1967 static immutable T
[6] P
= [
1968 6.931472028550421E-001L,
1969 2.402264791363012E-001L,
1970 5.550332471162809E-002L,
1971 9.618437357674640E-003L,
1972 1.339887440266574E-003L,
1973 1.535336188319500E-004L,
1977 static assert(0, "no coefficients for exp2()");
1979 // Overflow and Underflow limits.
1980 enum T OF
= T
.max_exp
;
1981 enum T UF
= T
.min_exp
- 1;
1987 return real.infinity
;
1991 static if (realFormat
== RealFormat
.ieeeSingle
) // special case for single precision
1993 // The following is necessary because range reduction blows up.
1997 // Separate into integer and fractional parts.
1998 const T i
= floor(x
);
1999 int n
= cast(int) i
;
2007 // Rational approximation:
2008 // exp2(x) = 1.0 + x P(x)
2009 x
= 1.0f + x
* poly(x
, P
);
2013 // Separate into integer and fractional parts.
2014 const T i
= floor(x
+ cast(T
) 0.5);
2015 int n
= cast(int) i
;
2018 // Rational approximation:
2019 // exp2(x) = 1.0 + 2x P(x^^2) / (Q(x^^2) - P(x^^2))
2021 const T px
= x
* poly(xx
, P
);
2022 x
= px
/ (poly(xx
, Q
) - px
);
2023 x
= (cast(T
) 1.0) + (cast(T
) 2.0) * x
;
2026 // Scale by power of 2.
2027 x
= core
.math
.ldexp(x
, n
);
2032 @safe @nogc nothrow unittest
2034 import std
.math
.operations
: feqrel
, NaN
, isClose
;
2035 import std
.math
.traits
: isIdentical
;
2036 import std
.math
.constants
: SQRT2
;
2038 assert(feqrel(exp2(0.5L), SQRT2
) >= real.mant_dig
-1);
2039 assert(exp2(8.0L) == 256.0);
2040 assert(exp2(-9.0L)== 1.0L/512.0);
2042 static void testExp2(T
)()
2045 const T specialNaN
= NaN(0x0123L
);
2046 assert(isIdentical(exp2(specialNaN
), specialNaN
));
2049 enum T OF
= T
.max_exp
;
2050 enum T UF
= T
.min_exp
- T
.mant_dig
;
2051 assert(isIdentical(exp2(OF
+ 1), cast(T
) T
.infinity
));
2052 assert(isIdentical(exp2(UF
- 1), cast(T
) 0.0));
2054 static immutable T
[2][] vals
=
2061 [ -9.0, 1.0 / 512 ],
2064 foreach (ref val
; vals
)
2068 const T e
= exp2(x
);
2070 //printf("exp2(%Lg) = %Lg, should be %Lg\n", cast(real) x, cast(real) e, cast(real) r);
2071 assert(isClose(r
, e
));
2075 import std
.meta
: AliasSeq
;
2076 foreach (T
; AliasSeq
!(real, double, float))
2080 /*********************************************************************
2081 * Separate floating point value into significand and exponent.
2084 * Calculate and return $(I x) and $(I exp) such that
2085 * value =$(I x)*2$(SUPERSCRIPT exp) and
2086 * .5 $(LT)= |$(I x)| $(LT) 1.0
2088 * $(I x) has same sign as value.
2091 * $(TR $(TH value) $(TH returns) $(TH exp))
2092 * $(TR $(TD $(PLUSMN)0.0) $(TD $(PLUSMN)0.0) $(TD 0))
2093 * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) $(TD int.max))
2094 * $(TR $(TD -$(INFIN)) $(TD -$(INFIN)) $(TD int.min))
2095 * $(TR $(TD $(PLUSMN)$(NAN)) $(TD $(PLUSMN)$(NAN)) $(TD int.min))
2098 T
frexp(T
)(const T value
, out int exp
) @trusted pure nothrow @nogc
2099 if (isFloatingPoint
!T
)
2101 import std
.math
: floatTraits
, RealFormat
, MANTISSA_MSB
, MANTISSA_LSB
;
2102 import std
.math
.traits
: isSubnormal
;
2106 // Handle special cases.
2107 if (value
== 0) { exp
= 0; return value
; }
2108 if (value
== T
.infinity
) { exp
= int.max
; return value
; }
2109 if (value
== -T
.infinity || value
!= value
) { exp
= int.min
; return value
; }
2110 // Handle ordinary cases.
2111 // In CTFE there is no performance advantage for having separate
2112 // paths for different floating point types.
2113 T absValue
= value
< 0 ?
-value
: value
;
2115 static if (T
.mant_dig
> double.mant_dig
)
2117 for (; absValue
>= 0x1.0p
+1024L; absValue
*= 0x1.0p
-1024L)
2119 for (; absValue
< 0x1.0p
-1021L; absValue
*= 0x1.0p
+1021L)
2122 const double dval
= cast(double) absValue
;
2123 int dexp
= cast(int) (((*cast(const long*) &dval
) >>> 52) & 0x7FF) + double.min_exp
- 2;
2126 absValue
*= 2.0 ^^
-dexp
;
2127 // If the original value was subnormal or if it was a real
2128 // then absValue can still be outside the [0.5, 1.0) range.
2131 assert(T
.mant_dig
> double.mant_dig ||
isSubnormal(value
));
2134 absValue
+= absValue
;
2136 } while (absValue
< 0.5);
2140 assert(absValue
< 1 || T
.mant_dig
> double.mant_dig
);
2141 for (; absValue
>= 1; absValue
*= T(0.5))
2145 return value
< 0 ?
-absValue
: absValue
;
2148 Unqual
!T vf
= value
;
2149 ushort* vu
= cast(ushort*)&vf
;
2150 static if (is(immutable T
== immutable float))
2151 int* vi
= cast(int*)&vf
;
2153 long* vl
= cast(long*)&vf
;
2155 alias F
= floatTraits
!T
;
2157 ex
= vu
[F
.EXPPOS_SHORT
] & F
.EXPMASK
;
2158 static if (F
.realFormat
== RealFormat
.ieeeExtended ||
2159 F
.realFormat
== RealFormat
.ieeeExtended53
)
2162 { // If exponent is non-zero
2163 if (ex
== F
.EXPMASK
) // infinity or NaN
2165 if (*vl
& 0x7FFF_FFFF_FFFF_FFFF
) // NaN
2167 *vl |
= 0xC000_0000_0000_0000; // convert NaNS to NaNQ
2170 else if (vu
[F
.EXPPOS_SHORT
] & 0x8000) // negative infinity
2172 else // positive infinity
2178 exp
= ex
- F
.EXPBIAS
;
2179 vu
[F
.EXPPOS_SHORT
] = (0x8000 & vu
[F
.EXPPOS_SHORT
]) |
0x3FFE;
2191 vf
*= F
.RECIP_EPSILON
;
2192 ex
= vu
[F
.EXPPOS_SHORT
] & F
.EXPMASK
;
2193 exp
= ex
- F
.EXPBIAS
- T
.mant_dig
+ 1;
2194 vu
[F
.EXPPOS_SHORT
] = ((-1 - F
.EXPMASK
) & vu
[F
.EXPPOS_SHORT
]) |
0x3FFE;
2198 else static if (F
.realFormat
== RealFormat
.ieeeQuadruple
)
2200 if (ex
) // If exponent is non-zero
2202 if (ex
== F
.EXPMASK
)
2205 if (vl
[MANTISSA_LSB
] |
2206 (vl
[MANTISSA_MSB
] & 0x0000_FFFF_FFFF_FFFF
)) // NaN
2208 // convert NaNS to NaNQ
2209 vl
[MANTISSA_MSB
] |
= 0x0000_8000_0000_0000;
2212 else if (vu
[F
.EXPPOS_SHORT
] & 0x8000) // negative infinity
2214 else // positive infinity
2219 exp
= ex
- F
.EXPBIAS
;
2220 vu
[F
.EXPPOS_SHORT
] = F
.EXPBIAS |
(0x8000 & vu
[F
.EXPPOS_SHORT
]);
2223 else if ((vl
[MANTISSA_LSB
] |
2224 (vl
[MANTISSA_MSB
] & 0x0000_FFFF_FFFF_FFFF
)) == 0)
2232 vf
*= F
.RECIP_EPSILON
;
2233 ex
= vu
[F
.EXPPOS_SHORT
] & F
.EXPMASK
;
2234 exp
= ex
- F
.EXPBIAS
- T
.mant_dig
+ 1;
2235 vu
[F
.EXPPOS_SHORT
] = F
.EXPBIAS |
(0x8000 & vu
[F
.EXPPOS_SHORT
]);
2239 else static if (F
.realFormat
== RealFormat
.ieeeDouble
)
2241 if (ex
) // If exponent is non-zero
2243 if (ex
== F
.EXPMASK
) // infinity or NaN
2245 if (*vl
== 0x7FF0_0000_0000_0000) // positive infinity
2249 else if (*vl
== 0xFFF0_0000_0000_0000) // negative infinity
2253 *vl |
= 0x0008_0000_0000_0000; // convert NaNS to NaNQ
2259 exp
= (ex
- F
.EXPBIAS
) >> 4;
2260 vu
[F
.EXPPOS_SHORT
] = cast(ushort)((0x800F & vu
[F
.EXPPOS_SHORT
]) |
0x3FE0);
2263 else if (!(*vl
& 0x7FFF_FFFF_FFFF_FFFF
))
2271 vf
*= F
.RECIP_EPSILON
;
2272 ex
= vu
[F
.EXPPOS_SHORT
] & F
.EXPMASK
;
2273 exp
= ((ex
- F
.EXPBIAS
) >> 4) - T
.mant_dig
+ 1;
2274 vu
[F
.EXPPOS_SHORT
] =
2275 cast(ushort)(((-1 - F
.EXPMASK
) & vu
[F
.EXPPOS_SHORT
]) |
0x3FE0);
2279 else static if (F
.realFormat
== RealFormat
.ieeeSingle
)
2281 if (ex
) // If exponent is non-zero
2283 if (ex
== F
.EXPMASK
) // infinity or NaN
2285 if (*vi
== 0x7F80_0000) // positive infinity
2289 else if (*vi
== 0xFF80_0000) // negative infinity
2293 *vi |
= 0x0040_0000; // convert NaNS to NaNQ
2299 exp
= (ex
- F
.EXPBIAS
) >> 7;
2300 vu
[F
.EXPPOS_SHORT
] = cast(ushort)((0x807F & vu
[F
.EXPPOS_SHORT
]) |
0x3F00);
2303 else if (!(*vi
& 0x7FFF_FFFF
))
2311 vf
*= F
.RECIP_EPSILON
;
2312 ex
= vu
[F
.EXPPOS_SHORT
] & F
.EXPMASK
;
2313 exp
= ((ex
- F
.EXPBIAS
) >> 7) - T
.mant_dig
+ 1;
2314 vu
[F
.EXPPOS_SHORT
] =
2315 cast(ushort)(((-1 - F
.EXPMASK
) & vu
[F
.EXPPOS_SHORT
]) |
0x3F00);
2319 else // static if (F.realFormat == RealFormat.ibmExtended)
2321 assert(0, "frexp not implemented");
2328 import std
.math
.operations
: isClose
;
2331 real mantissa
= frexp(123.456L, exp
);
2333 assert(isClose(mantissa
* pow(2.0L, cast(real) exp
), 123.456L));
2335 assert(frexp(-real.nan
, exp
) && exp
== int.min
);
2336 assert(frexp(real.nan
, exp
) && exp
== int.min
);
2337 assert(frexp(-real.infinity
, exp
) == -real.infinity
&& exp
== int.min
);
2338 assert(frexp(real.infinity
, exp
) == real.infinity
&& exp
== int.max
);
2339 assert(frexp(-0.0, exp
) == -0.0 && exp
== 0);
2340 assert(frexp(0.0, exp
) == 0.0 && exp
== 0);
2343 @safe @nogc nothrow unittest
2345 import std
.math
.operations
: isClose
;
2348 real mantissa
= frexp(123.456L, exp
);
2350 // check if values are equal to 19 decimal digits of precision
2351 assert(isClose(mantissa
* pow(2.0L, cast(real) exp
), 123.456L, 1e-18));
2356 import std
.math
: floatTraits
, RealFormat
;
2357 import std
.math
.traits
: isIdentical
;
2358 import std
.meta
: AliasSeq
;
2359 import std
.typecons
: tuple
, Tuple
;
2361 static foreach (T
; AliasSeq
!(real, double, float))
2363 Tuple
!(T
, T
, int)[] vals
= [ // x,frexp,exp
2364 tuple(T(0.0), T( 0.0 ), 0),
2365 tuple(T(-0.0), T( -0.0), 0),
2366 tuple(T(1.0), T( .5 ), 1),
2367 tuple(T(-1.0), T( -.5 ), 1),
2368 tuple(T(2.0), T( .5 ), 2),
2369 tuple(T(float.min_normal
/2.0f), T(.5), -126),
2370 tuple(T
.infinity
, T
.infinity
, int.max
),
2371 tuple(-T
.infinity
, -T
.infinity
, int.min
),
2372 tuple(T
.nan
, T
.nan
, int.min
),
2373 tuple(-T
.nan
, -T
.nan
, int.min
),
2375 // https://issues.dlang.org/show_bug.cgi?id=16026:
2376 tuple(3 * (T
.min_normal
* T
.epsilon
), T( .75), (T
.min_exp
- T
.mant_dig
) + 2)
2379 foreach (elem
; vals
)
2385 T v
= frexp(x
, eptr
);
2386 assert(isIdentical(e
, v
));
2387 assert(exp
== eptr
);
2390 static if (floatTraits
!(T
).realFormat
== RealFormat
.ieeeExtended
)
2392 static T
[3][] extendedvals
= [ // x,frexp,exp
2393 [0x1.a5f1c2eb3fe4efp
+73L, 0x1.A5F1C2EB3FE4EFp
-1L, 74], // normal
2394 [0x1.fa01712e8f0471ap
-1064L, 0x1.fa01712e8f0471ap
-1L, -1063],
2395 [T
.min_normal
, .5, -16381],
2396 [T
.min_normal
/2.0L, .5, -16382] // subnormal
2398 foreach (elem
; extendedvals
)
2402 int exp
= cast(int) elem
[2];
2404 T v
= frexp(x
, eptr
);
2405 assert(isIdentical(e
, v
));
2406 assert(exp
== eptr
);
2412 alias CtfeFrexpResult
= Tuple
!(real, int);
2413 static CtfeFrexpResult
ctfeFrexp(T
)(const T value
)
2416 auto significand
= frexp(value
, exp
);
2417 return CtfeFrexpResult(significand
, exp
);
2419 static foreach (T
; AliasSeq
!(real, double, float))
2421 enum Tuple
!(T
, T
, int)[] vals
= [ // x,frexp,exp
2422 tuple(T(0.0), T( 0.0 ), 0),
2423 tuple(T(-0.0), T( -0.0), 0),
2424 tuple(T(1.0), T( .5 ), 1),
2425 tuple(T(-1.0), T( -.5 ), 1),
2426 tuple(T(2.0), T( .5 ), 2),
2427 tuple(T(float.min_normal
/2.0f), T(.5), -126),
2428 tuple(T
.infinity
, T
.infinity
, int.max
),
2429 tuple(-T
.infinity
, -T
.infinity
, int.min
),
2430 tuple(T
.nan
, T
.nan
, int.min
),
2431 tuple(-T
.nan
, -T
.nan
, int.min
),
2433 // https://issues.dlang.org/show_bug.cgi?id=16026:
2434 tuple(3 * (T
.min_normal
* T
.epsilon
), T( .75), (T
.min_exp
- T
.mant_dig
) + 2)
2437 static foreach (elem
; vals
)
2439 static assert(ctfeFrexp(elem
[0]) is CtfeFrexpResult(elem
[1], elem
[2]));
2442 static if (floatTraits
!(T
).realFormat
== RealFormat
.ieeeExtended
)
2444 enum T
[3][] extendedvals
= [ // x,frexp,exp
2445 [0x1.a5f1c2eb3fe4efp
+73L, 0x1.A5F1C2EB3FE4EFp
-1L, 74], // normal
2446 [0x1.fa01712e8f0471ap
-1064L, 0x1.fa01712e8f0471ap
-1L, -1063],
2447 [T
.min_normal
, .5, -16381],
2448 [T
.min_normal
/2.0L, .5, -16382] // subnormal
2450 static foreach (elem
; extendedvals
)
2452 static assert(ctfeFrexp(elem
[0]) is CtfeFrexpResult(elem
[1], cast(int) elem
[2]));
2460 import std
.meta
: AliasSeq
;
2462 static foreach (T
; AliasSeq
!(real, double, float))
2467 auto c
= frexp(a
, exp
);
2468 auto d
= frexp(b
, exp
);
2473 /******************************************
2474 * Extracts the exponent of x as a signed integral value.
2476 * If x is not a special value, the result is the same as
2477 * $(D cast(int) logb(x)).
2480 * $(TR $(TH x) $(TH ilogb(x)) $(TH Range error?))
2481 * $(TR $(TD 0) $(TD FP_ILOGB0) $(TD yes))
2482 * $(TR $(TD $(PLUSMN)$(INFIN)) $(TD int.max) $(TD no))
2483 * $(TR $(TD $(NAN)) $(TD FP_ILOGBNAN) $(TD no))
2486 int ilogb(T
)(const T x
) @trusted pure nothrow @nogc
2487 if (isFloatingPoint
!T
)
2489 import std
.math
: floatTraits
, RealFormat
, MANTISSA_MSB
, MANTISSA_LSB
;
2491 import core
.bitop
: bsr;
2492 alias F
= floatTraits
!T
;
2497 ushort[T
.sizeof
/2] vu
;
2498 uint[T
.sizeof
/4] vui
;
2499 static if (T
.sizeof
>= 8)
2500 ulong[T
.sizeof
/8] vul
;
2505 int ex
= y
.vu
[F
.EXPPOS_SHORT
] & F
.EXPMASK
;
2506 static if (F
.realFormat
== RealFormat
.ieeeExtended ||
2507 F
.realFormat
== RealFormat
.ieeeExtended53
)
2511 // If exponent is non-zero
2512 if (ex
== F
.EXPMASK
) // infinity or NaN
2514 if (y
.vul
[0] & 0x7FFF_FFFF_FFFF_FFFF
) // NaN
2521 return ex
- F
.EXPBIAS
- 1;
2532 return ex
- F
.EXPBIAS
- T
.mant_dig
+ 1 + bsr(y
.vul
[0]);
2535 else static if (F
.realFormat
== RealFormat
.ieeeQuadruple
)
2537 if (ex
) // If exponent is non-zero
2539 if (ex
== F
.EXPMASK
)
2542 if (y
.vul
[MANTISSA_LSB
] |
( y
.vul
[MANTISSA_MSB
] & 0x0000_FFFF_FFFF_FFFF
)) // NaN
2549 return ex
- F
.EXPBIAS
- 1;
2552 else if ((y
.vul
[MANTISSA_LSB
] |
(y
.vul
[MANTISSA_MSB
] & 0x0000_FFFF_FFFF_FFFF
)) == 0)
2560 const ulong msb
= y
.vul
[MANTISSA_MSB
] & 0x0000_FFFF_FFFF_FFFF
;
2561 const ulong lsb
= y
.vul
[MANTISSA_LSB
];
2563 return ex
- F
.EXPBIAS
- T
.mant_dig
+ 1 + bsr(msb
) + 64;
2565 return ex
- F
.EXPBIAS
- T
.mant_dig
+ 1 + bsr(lsb
);
2568 else static if (F
.realFormat
== RealFormat
.ieeeDouble
)
2570 if (ex
) // If exponent is non-zero
2572 if (ex
== F
.EXPMASK
) // infinity or NaN
2574 if ((y
.vul
[0] & 0x7FFF_FFFF_FFFF_FFFF
) == 0x7FF0_0000_0000_0000) // +- infinity
2581 return ((ex
- F
.EXPBIAS
) >> 4) - 1;
2584 else if (!(y
.vul
[0] & 0x7FFF_FFFF_FFFF_FFFF
))
2592 enum MANTISSAMASK_64
= ((cast(ulong) F
.MANTISSAMASK_INT
) << 32) |
0xFFFF_FFFF
;
2593 return ((ex
- F
.EXPBIAS
) >> 4) - T
.mant_dig
+ 1 + bsr(y
.vul
[0] & MANTISSAMASK_64
);
2596 else static if (F
.realFormat
== RealFormat
.ieeeSingle
)
2598 if (ex
) // If exponent is non-zero
2600 if (ex
== F
.EXPMASK
) // infinity or NaN
2602 if ((y
.vui
[0] & 0x7FFF_FFFF
) == 0x7F80_0000) // +- infinity
2609 return ((ex
- F
.EXPBIAS
) >> 7) - 1;
2612 else if (!(y
.vui
[0] & 0x7FFF_FFFF
))
2620 const uint mantissa
= y
.vui
[0] & F
.MANTISSAMASK_INT
;
2621 return ((ex
- F
.EXPBIAS
) >> 7) - T
.mant_dig
+ 1 + bsr(mantissa
);
2624 else // static if (F.realFormat == RealFormat.ibmExtended)
2626 assert(0, "ilogb not implemented");
2630 int ilogb(T
)(const T x
) @safe pure nothrow @nogc
2631 if (isIntegral
!T
&& isUnsigned
!T
)
2633 import core
.bitop
: bsr;
2638 static assert(T
.sizeof
<= ulong.sizeof
, "integer size too large for the current ilogb implementation");
2643 int ilogb(T
)(const T x
) @safe pure nothrow @nogc
2644 if (isIntegral
!T
&& isSigned
!T
)
2646 import std
.traits
: Unsigned
;
2647 // Note: abs(x) can not be used because the return type is not Unsigned and
2648 // the return value would be wrong for x == int.min
2649 Unsigned
!T absx
= x
>= 0 ? x
: -x
;
2656 assert(ilogb(1) == 0);
2657 assert(ilogb(3) == 1);
2658 assert(ilogb(3.0) == 1);
2659 assert(ilogb(100_000_000) == 26);
2661 assert(ilogb(0) == FP_ILOGB0
);
2662 assert(ilogb(0.0) == FP_ILOGB0
);
2663 assert(ilogb(double.nan
) == FP_ILOGBNAN
);
2664 assert(ilogb(double.infinity
) == int.max
);
2668 Special return values of $(LREF ilogb).
2670 alias FP_ILOGB0
= core
.stdc
.math
.FP_ILOGB0
;
2672 alias FP_ILOGBNAN
= core
.stdc
.math
.FP_ILOGBNAN
;
2677 assert(ilogb(0) == FP_ILOGB0
);
2678 assert(ilogb(0.0) == FP_ILOGB0
);
2679 assert(ilogb(double.nan
) == FP_ILOGBNAN
);
2682 @safe nothrow @nogc unittest
2684 import std
.math
: floatTraits
, RealFormat
;
2685 import std
.math
.operations
: nextUp
;
2686 import std
.meta
: AliasSeq
;
2687 import std
.typecons
: Tuple
;
2688 static foreach (F
; AliasSeq
!(float, double, real))
2690 alias T
= Tuple
!(F
, int);
2691 T
[13] vals
= // x, ilogb(x)
2693 T( F
.nan
, FP_ILOGBNAN
),
2694 T( -F
.nan
, FP_ILOGBNAN
),
2695 T( F
.infinity
, int.max
),
2696 T( -F
.infinity
, int.max
),
2697 T( 0.0 , FP_ILOGB0
),
2698 T( -0.0 , FP_ILOGB0
),
2708 foreach (elem
; vals
)
2710 assert(ilogb(elem
[0]) == elem
[1]);
2714 // min_normal and subnormals
2715 assert(ilogb(-float.min_normal
) == -126);
2716 assert(ilogb(nextUp(-float.min_normal
)) == -127);
2717 assert(ilogb(nextUp(-float(0.0))) == -149);
2718 assert(ilogb(-double.min_normal
) == -1022);
2719 assert(ilogb(nextUp(-double.min_normal
)) == -1023);
2720 assert(ilogb(nextUp(-double(0.0))) == -1074);
2721 static if (floatTraits
!(real).realFormat
== RealFormat
.ieeeExtended
)
2723 assert(ilogb(-real.min_normal
) == -16382);
2724 assert(ilogb(nextUp(-real.min_normal
)) == -16383);
2725 assert(ilogb(nextUp(-real(0.0))) == -16445);
2727 else static if (floatTraits
!(real).realFormat
== RealFormat
.ieeeDouble
)
2729 assert(ilogb(-real.min_normal
) == -1022);
2730 assert(ilogb(nextUp(-real.min_normal
)) == -1023);
2731 assert(ilogb(nextUp(-real(0.0))) == -1074);
2734 // test integer types
2735 assert(ilogb(0) == FP_ILOGB0
);
2736 assert(ilogb(int.max
) == 30);
2737 assert(ilogb(int.min
) == 31);
2738 assert(ilogb(uint.max
) == 31);
2739 assert(ilogb(long.max
) == 62);
2740 assert(ilogb(long.min
) == 63);
2741 assert(ilogb(ulong.max
) == 63);
2744 /*******************************************
2745 * Compute n * 2$(SUPERSCRIPT exp)
2749 pragma(inline
, true)
2750 real ldexp(real n
, int exp
) @safe pure nothrow @nogc { return core
.math
.ldexp(n
, exp
); }
2752 pragma(inline
, true)
2753 double ldexp(double n
, int exp
) @safe pure nothrow @nogc { return core
.math
.ldexp(n
, exp
); }
2755 pragma(inline
, true)
2756 float ldexp(float n
, int exp
) @safe pure nothrow @nogc { return core
.math
.ldexp(n
, exp
); }
2759 @nogc @safe pure nothrow unittest
2761 import std
.meta
: AliasSeq
;
2762 static foreach (T
; AliasSeq
!(float, double, real))
2769 r
= ldexp(cast(T
) 3.0, cast(int) 3);
2779 @safe pure nothrow @nogc unittest
2781 import std
.math
: floatTraits
, RealFormat
;
2783 static if (floatTraits
!(real).realFormat
== RealFormat
.ieeeExtended ||
2784 floatTraits
!(real).realFormat
== RealFormat
.ieeeExtended53 ||
2785 floatTraits
!(real).realFormat
== RealFormat
.ieeeQuadruple
)
2787 assert(ldexp(1.0L, -16384) == 0x1p
-16384L);
2788 assert(ldexp(1.0L, -16382) == 0x1p
-16382L);
2790 real n
= frexp(0x1p
-16384L, x
);
2793 assert(ldexp(n
, x
)==0x1p
-16384L);
2795 else static if (floatTraits
!(real).realFormat
== RealFormat
.ieeeDouble
)
2797 assert(ldexp(1.0L, -1024) == 0x1p
-1024L);
2798 assert(ldexp(1.0L, -1022) == 0x1p
-1022L);
2800 real n
= frexp(0x1p
-1024L, x
);
2803 assert(ldexp(n
, x
)==0x1p
-1024L);
2805 else static assert(false, "Floating point type real not supported");
2808 /* workaround https://issues.dlang.org/show_bug.cgi?id=14718
2809 float parsing depends on platform strtold
2810 @safe pure nothrow @nogc unittest
2812 assert(ldexp(1.0, -1024) == 0x1p-1024);
2813 assert(ldexp(1.0, -1022) == 0x1p-1022);
2815 double n = frexp(0x1p-1024, x);
2818 assert(ldexp(n, x)==0x1p-1024);
2821 @safe pure nothrow @nogc unittest
2823 assert(ldexp(1.0f, -128) == 0x1p-128f);
2824 assert(ldexp(1.0f, -126) == 0x1p-126f);
2826 float n = frexp(0x1p-128f, x);
2829 assert(ldexp(n, x)==0x1p-128f);
2833 @safe @nogc nothrow unittest
2835 import std
.math
.operations
: isClose
;
2837 static real[3][] vals
= // value,exp,ldexp
2844 [ real.max
, int.max
, real.infinity
],
2845 [ real.max
, -int.max
, 0],
2846 [ real.min_normal
, -int.max
, 0],
2850 for (i
= 0; i
< vals
.length
; i
++)
2852 real x
= vals
[i
][0];
2853 int exp
= cast(int) vals
[i
][1];
2854 real z
= vals
[i
][2];
2855 real l
= ldexp(x
, exp
);
2857 assert(isClose(z
, l
, 1e-6));
2860 real function(real, int) pldexp
= &ldexp
;
2861 assert(pldexp
!= null);
2866 // Coefficients shared across log(), log2(), log10(), log1p().
2867 template LogCoeffs(T
)
2869 import std
.math
: floatTraits
, RealFormat
;
2871 static if (floatTraits
!T
.realFormat
== RealFormat
.ieeeQuadruple
)
2873 // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x)/Q(x)
2874 // Theoretical peak relative error = 5.3e-37
2875 static immutable real[13] logP
= [
2876 1.313572404063446165910279910527789794488E4L
,
2877 7.771154681358524243729929227226708890930E4L
,
2878 2.014652742082537582487669938141683759923E5L
,
2879 3.007007295140399532324943111654767187848E5L
,
2880 2.854829159639697837788887080758954924001E5L
,
2881 1.797628303815655343403735250238293741397E5L
,
2882 7.594356839258970405033155585486712125861E4L
,
2883 2.128857716871515081352991964243375186031E4L
,
2884 3.824952356185897735160588078446136783779E3L
,
2885 4.114517881637811823002128927449878962058E2L
,
2886 2.321125933898420063925789532045674660756E1L
,
2887 4.998469661968096229986658302195402690910E-1L,
2888 1.538612243596254322971797716843006400388E-6L
2890 static immutable real[13] logQ
= [
2891 3.940717212190338497730839731583397586124E4L
,
2892 2.626900195321832660448791748036714883242E5L
,
2893 7.777690340007566932935753241556479363645E5L
,
2894 1.347518538384329112529391120390701166528E6L
,
2895 1.514882452993549494932585972882995548426E6L
,
2896 1.158019977462989115839826904108208787040E6L
,
2897 6.132189329546557743179177159925690841200E5L
,
2898 2.248234257620569139969141618556349415120E5L
,
2899 5.605842085972455027590989944010492125825E4L
,
2900 9.147150349299596453976674231612674085381E3L
,
2901 9.104928120962988414618126155557301584078E2L
,
2902 4.839208193348159620282142911143429644326E1L
,
2906 // log2 uses the same coefficients as log.
2910 // log10 uses the same coefficients as log.
2911 alias log10P
= logP
;
2912 alias log10Q
= logQ
;
2914 // Coefficients for log(x) = z + z^^3 R(z^^2)/S(z^^2)
2915 // where z = 2(x-1)/(x+1)
2916 // Theoretical peak relative error = 1.1e-35
2917 static immutable real[6] logR
= [
2918 1.418134209872192732479751274970992665513E5L
,
2919 -8.977257995689735303686582344659576526998E4L
,
2920 2.048819892795278657810231591630928516206E4L
,
2921 -2.024301798136027039250415126250455056397E3L
,
2922 8.057002716646055371965756206836056074715E1L
,
2923 -8.828896441624934385266096344596648080902E-1L
2925 static immutable real[7] logS
= [
2926 1.701761051846631278975701529965589676574E6L
,
2927 -1.332535117259762928288745111081235577029E6L
,
2928 4.001557694070773974936904547424676279307E5L
,
2929 -5.748542087379434595104154610899551484314E4L
,
2930 3.998526750980007367835804959888064681098E3L
,
2931 -1.186359407982897997337150403816839480438E2L
,
2935 else static if (floatTraits
!T
.realFormat
== RealFormat
.ieeeExtended ||
2936 floatTraits
!T
.realFormat
== RealFormat
.ieeeExtended53
)
2938 // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x)/Q(x)
2939 // Theoretical peak relative error = 2.32e-20
2940 static immutable real[7] logP
= [
2941 2.0039553499201281259648E1L
,
2942 5.7112963590585538103336E1L
,
2943 6.0949667980987787057556E1L
,
2944 2.9911919328553073277375E1L
,
2945 6.5787325942061044846969E0L
,
2946 4.9854102823193375972212E-1L,
2947 4.5270000862445199635215E-5L,
2949 static immutable real[7] logQ
= [
2950 6.0118660497603843919306E1L
,
2951 2.1642788614495947685003E2L
,
2952 3.0909872225312059774938E2L
,
2953 2.2176239823732856465394E2L
,
2954 8.3047565967967209469434E1L
,
2955 1.5062909083469192043167E1L
,
2956 1.0000000000000000000000E0L
,
2959 // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x)/Q(x)
2960 // Theoretical peak relative error = 6.2e-22
2961 static immutable real[7] log2P
= [
2962 1.0747524399916215149070E2L
,
2963 3.4258224542413922935104E2L
,
2964 4.2401812743503691187826E2L
,
2965 2.5620629828144409632571E2L
,
2966 7.7671073698359539859595E1L
,
2967 1.0767376367209449010438E1L
,
2968 4.9962495940332550844739E-1L,
2970 static immutable real[8] log2Q
= [
2971 3.2242573199748645407652E2L
,
2972 1.2695660352705325274404E3L
,
2973 2.0307734695595183428202E3L
,
2974 1.6911722418503949084863E3L
,
2975 7.7952888181207260646090E2L
,
2976 1.9444210022760132894510E2L
,
2977 2.3479774160285863271658E1L
,
2978 1.0000000000000000000000E0
,
2981 // log10 uses the same coefficients as log2.
2982 alias log10P
= log2P
;
2983 alias log10Q
= log2Q
;
2985 // Coefficients for log(x) = z + z^^3 R(z^^2)/S(z^^2)
2986 // where z = 2(x-1)/(x+1)
2987 // Theoretical peak relative error = 6.16e-22
2988 static immutable real[4] logR
= [
2989 -3.5717684488096787370998E1L
,
2990 1.0777257190312272158094E1L
,
2991 -7.1990767473014147232598E-1L,
2992 1.9757429581415468984296E-3L,
2994 static immutable real[4] logS
= [
2995 -4.2861221385716144629696E2L
,
2996 1.9361891836232102174846E2L
,
2997 -2.6201045551331104417768E1L
,
2998 1.0000000000000000000000E0L
,
3001 else static if (floatTraits
!T
.realFormat
== RealFormat
.ieeeDouble
)
3003 // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x)/Q(x)
3004 static immutable double[6] logP
= [
3005 7.70838733755885391666E0
,
3006 1.79368678507819816313E1
,
3007 1.44989225341610930846E1
,
3008 4.70579119878881725854E0
,
3009 4.97494994976747001425E-1,
3010 1.01875663804580931796E-4,
3012 static immutable double[6] logQ
= [
3013 2.31251620126765340583E1
,
3014 7.11544750618563894466E1
,
3015 8.29875266912776603211E1
,
3016 4.52279145837532221105E1
,
3017 1.12873587189167450590E1
,
3018 1.00000000000000000000E0
,
3021 // log2 uses the same coefficients as log.
3025 // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x)/Q(x)
3026 static immutable double[7] logp1P
= [
3027 2.0039553499201281259648E1
,
3028 5.7112963590585538103336E1
,
3029 6.0949667980987787057556E1
,
3030 2.9911919328553073277375E1
,
3031 6.5787325942061044846969E0
,
3032 4.9854102823193375972212E-1,
3033 4.5270000862445199635215E-5,
3035 static immutable double[7] logp1Q
= [
3036 1.0000000000000000000000E0
,
3037 6.0118660497603843919306E1
,
3038 2.1642788614495947685003E2
,
3039 3.0909872225312059774938E2
,
3040 2.2176239823732856465394E2
,
3041 8.3047565967967209469434E1
,
3042 1.5062909083469192043167E1
,
3045 static immutable double[7] log10P
= [
3046 1.98892446572874072159E1
,
3047 5.67349287391754285487E1
,
3048 6.06127134467767258030E1
,
3049 2.97877425097986925891E1
,
3050 6.56312093769992875930E0
,
3051 4.98531067254050724270E-1,
3052 4.58482948458143443514E-5,
3054 static immutable double[7] log10Q
= [
3055 5.96677339718622216300E1
,
3056 2.14955586696422947765E2
,
3057 3.07254189979530058263E2
,
3058 2.20664384982121929218E2
,
3059 8.27410449222435217021E1
,
3060 1.50314182634250003249E1
,
3061 1.00000000000000000000E0
,
3064 // Coefficients for log(x) = z + z^^3 R(z)/S(z)
3065 // where z = 2(x-1)/(x+1)
3066 static immutable double[3] logR
= [
3067 -6.41409952958715622951E1
,
3068 1.63866645699558079767E1
,
3069 -7.89580278884799154124E-1,
3071 static immutable double[4] logS
= [
3072 -7.69691943550460008604E2
,
3073 3.12093766372244180303E2
,
3074 -3.56722798256324312549E1
,
3075 1.00000000000000000000E0
,
3078 else static if (floatTraits
!T
.realFormat
== RealFormat
.ieeeSingle
)
3080 // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x)
3081 static immutable float[9] logP
= [
3093 // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x)/Q(x)
3094 static immutable float[7] logp1P
= [
3103 static immutable float[7] logp1Q
= [
3113 // log2 and log10 uses the same coefficients as log.
3115 alias log10P
= logP
;
3118 static assert(0, "no coefficients for log()");
3122 /**************************************
3123 * Calculate the natural logarithm of x.
3126 * $(TR $(TH x) $(TH log(x)) $(TH divide by 0?) $(TH invalid?))
3127 * $(TR $(TD $(PLUSMN)0.0) $(TD -$(INFIN)) $(TD yes) $(TD no))
3128 * $(TR $(TD $(LT)0.0) $(TD $(NAN)) $(TD no) $(TD yes))
3129 * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) $(TD no) $(TD no))
3132 pragma(inline
, true)
3133 real log(real x
) @safe pure nothrow @nogc
3135 version (INLINE_YL2X
)
3137 import std
.math
.constants
: LN2
;
3138 return core
.math
.yl2x(x
, LN2
);
3145 pragma(inline
, true)
3146 double log(double x
) @safe pure nothrow @nogc { return __ctfe ?
cast(double) log(cast(real) x
) : logImpl(x
); }
3149 pragma(inline
, true)
3150 float log(float x
) @safe pure nothrow @nogc { return __ctfe ?
cast(float) log(cast(real) x
) : logImpl(x
); }
3152 // @@@DEPRECATED_[2.112.0]@@@
3153 deprecated("`std.math.exponential.log` called with argument types `(int)` matches both "
3154 ~ "`log(real)`, `log(double)`, and `log(float)`. Cast argument to floating point type instead.")
3155 real log(int 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 `(uint)` matches both "
3158 ~ "`log(real)`, `log(double)`, and `log(float)`. Cast argument to floating point type instead.")
3159 real log(uint 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 `(long)` matches both "
3162 ~ "`log(real)`, `log(double)`, and `log(float)`. Cast argument to floating point type instead.")
3163 real log(long x
) @safe pure nothrow @nogc { return log(cast(real) x
); }
3164 // @@@DEPRECATED_[2.112.0]@@@
3165 deprecated("`std.math.exponential.log` called with argument types `(ulong)` matches both "
3166 ~ "`log(real)`, `log(double)`, and `log(float)`. Cast argument to floating point type instead.")
3167 real log(ulong x
) @safe pure nothrow @nogc { return log(cast(real) x
); }
3170 @safe pure nothrow @nogc unittest
3172 import std
.math
.operations
: feqrel
;
3173 import std
.math
.constants
: E
;
3175 assert(feqrel(log(E
), 1) >= real.mant_dig
- 1);
3178 private T
logImpl(T
, bool LOG1P
= false)(T x
) @safe pure nothrow @nogc
3180 import std
.math
.constants
: SQRT1_2
;
3181 import std
.math
.algebraic
: poly
;
3182 import std
.math
.traits
: isInfinity
, isNaN
, signbit
;
3183 import std
.math
: floatTraits
, RealFormat
;
3185 alias coeffs
= LogCoeffs
!T
;
3186 alias F
= floatTraits
!T
;
3194 static if (F
.realFormat
== RealFormat
.ieeeExtended ||
3195 F
.realFormat
== RealFormat
.ieeeExtended53 ||
3196 F
.realFormat
== RealFormat
.ieeeQuadruple
)
3199 enum T C1
= 6.93145751953125E-1L;
3200 enum T C2
= 1.428606820309417232121458176568075500134E-6L;
3202 else static if (F
.realFormat
== RealFormat
.ieeeDouble
)
3204 enum T C1
= 0.693359375;
3205 enum T C2
= -2.121944400546905827679e-4;
3207 else static if (F
.realFormat
== RealFormat
.ieeeSingle
)
3209 enum T C1
= 0.693359375;
3210 enum T C2
= -2.12194440e-4;
3213 static assert(0, "Not implemented for this architecture");
3218 if (isInfinity(x
) && !signbit(x
))
3225 // Separate mantissa from exponent.
3226 // Note, frexp is used so that denormal numbers will be handled properly.
3232 static if (F
.realFormat
== RealFormat
.ieeeDouble ||
3233 F
.realFormat
== RealFormat
.ieeeExtended ||
3234 F
.realFormat
== RealFormat
.ieeeExtended53 ||
3235 F
.realFormat
== RealFormat
.ieeeQuadruple
)
3237 // Logarithm using log(x) = z + z^^3 R(z) / S(z),
3238 // where z = 2(x - 1)/(x + 1)
3239 if ((exp
> 2) ||
(exp
< -2))
3242 { // 2(2x - 1)/(2x + 1)
3248 { // 2(x - 1)/(x + 1)
3255 z
= x
* (z
* poly(z
, coeffs
.logR
) / poly(z
, coeffs
.logS
));
3264 // Logarithm using log(1 + x) = x - .5x^^2 + x^^3 P(x) / Q(x)
3292 static if (F
.realFormat
== RealFormat
.ieeeSingle
)
3293 y
= x
* (z
* poly(x
, coeffs
.logP
));
3295 y
= x
* (z
* poly(x
, coeffs
.logP
) / poly(x
, coeffs
.logQ
));
3299 // Note, the sum of above terms does not exceed x/4,
3300 // so it contributes at most about 1/4 lsb to the error.
3307 @safe @nogc nothrow unittest
3309 import std
.math
: floatTraits
, RealFormat
;
3310 import std
.meta
: AliasSeq
;
3312 static void testLog(T
)(T
[2][] vals
)
3314 import std
.math
.operations
: isClose
;
3315 import std
.math
.traits
: isNaN
;
3316 foreach (ref pair
; vals
)
3319 assert(isNaN(log(pair
[0])));
3321 assert(isClose(log(pair
[0]), pair
[1]));
3324 static foreach (F
; AliasSeq
!(float, double, real))
3327 [F(1), F(0x0p
+0)], [F(2), F(0x1.62e42fefa39ef358p
-1)],
3328 [F(4), F(0x1.62e42fefa39ef358p
+0)], [F(8), F(0x1.0a2b23f3bab73682p
+1)],
3329 [F(16), F(0x1.62e42fefa39ef358p
+1)], [F(32), F(0x1.bb9d3beb8c86b02ep
+1)],
3330 [F(64), F(0x1.0a2b23f3bab73682p
+2)], [F(128), F(0x1.3687a9f1af2b14ecp
+2)],
3331 [F(256), F(0x1.62e42fefa39ef358p
+2)], [F(512), F(0x1.8f40b5ed
9812d1c
2p
+2)],
3332 [F(1024), F(0x1.bb9d3beb8c86b02ep
+2)], [F(2048), F(0x1.e7f9c1e980fa8e98p
+2)],
3333 [F(3), F(0x1.193ea7aad030a976p
+0)], [F(5), F(0x1.9c041f7ed8d336bp
+0)],
3334 [F(7), F(0x1.f2272ae325a57546p
+0)], [F(15), F(0x1.5aa16394d481f014p
+1)],
3335 [F(17), F(0x1.6aa6bc1fa7f79cfp
+1)], [F(31), F(0x1.b78ce48912b59f12p
+1)],
3336 [F(33), F(0x1.bf8d8f4d5b8d1038p
+1)], [F(63), F(0x1.09291e8e3181b20ep
+2)],
3337 [F(65), F(0x1.0b292939429755ap
+2)], [F(-0), -F
.infinity
], [F(0), -F
.infinity
],
3338 [F(10000), F(0x1.26bb1bbb5551582ep
+3)],
3343 float[2][16] vals
= [
3344 [float.nan
, float.nan
],[-float.nan
, float.nan
],
3345 [float.infinity
, float.infinity
], [-float.infinity
, float.nan
],
3346 [float.min_normal
, -0x1.5d58ap
+6f], [-float.min_normal
, float.nan
],
3347 [float.max
, 0x1.62e43p
+6f], [-float.max
, float.nan
],
3348 [float.min_normal
/ 2, -0x1.601e68p
+6f], [-float.min_normal
/ 2, float.nan
],
3349 [float.max
/ 2, 0x1.601e68p
+6f], [-float.max
/ 2, float.nan
],
3350 [float.min_normal
/ 3, -0x1.61bd9ap
+6f], [-float.min_normal
/ 3, float.nan
],
3351 [float.max
/ 3, 0x1.5e7f36p
+6f], [-float.max
/ 3, float.nan
],
3356 double[2][16] vals
= [
3357 [double.nan
, double.nan
],[-double.nan
, double.nan
],
3358 [double.infinity
, double.infinity
], [-double.infinity
, double.nan
],
3359 [double.min_normal
, -0x1.6232bdd7abcd
2p
+9], [-double.min_normal
, double.nan
],
3360 [double.max
, 0x1.62e42fefa39efp
+9], [-double.max
, double.nan
],
3361 [double.min_normal
/ 2, -0x1.628b76e
3a
7b61p
+9], [-double.min_normal
/ 2, double.nan
],
3362 [double.max
/ 2, 0x1.628b76e
3a
7b61p
+9], [-double.max
/ 2, double.nan
],
3363 [double.min_normal
/ 3, -0x1.62bf5d2b81354p
+9], [-double.min_normal
/ 3, double.nan
],
3364 [double.max
/ 3, 0x1.6257909bce
36ep
+9], [-double.max
/ 3, double.nan
],
3368 alias F
= floatTraits
!real;
3369 static if (F
.realFormat
== RealFormat
.ieeeExtended || F
.realFormat
== RealFormat
.ieeeQuadruple
)
3371 real[2][16] vals
= [
3372 [real.nan
, real.nan
],[-real.nan
, real.nan
],
3373 [real.infinity
, real.infinity
], [-real.infinity
, real.nan
],
3374 [real.min_normal
, -0x1.62d918ce
2421d66p
+13L], [-real.min_normal
, real.nan
],
3375 [real.max
, 0x1.62e42fefa39ef358p
+13L], [-real.max
, real.nan
],
3376 [real.min_normal
/ 2, -0x1.62dea
45ee
3e
064dcp
+13L], [-real.min_normal
/ 2, real.nan
],
3377 [real.max
/ 2, 0x1.62dea
45ee
3e
064dcp
+13L], [-real.max
/ 2, real.nan
],
3378 [real.min_normal
/ 3, -0x1.62e1e2c3617857e6p
+13L], [-real.min_normal
/ 3, real.nan
],
3379 [real.max
/ 3, 0x1.62db65fa
664871d2p
+13L], [-real.max
/ 3, real.nan
],
3385 /**************************************
3386 * Calculate the base-10 logarithm of x.
3389 * $(TR $(TH x) $(TH log10(x)) $(TH divide by 0?) $(TH invalid?))
3390 * $(TR $(TD $(PLUSMN)0.0) $(TD -$(INFIN)) $(TD yes) $(TD no))
3391 * $(TR $(TD $(LT)0.0) $(TD $(NAN)) $(TD no) $(TD yes))
3392 * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) $(TD no) $(TD no))
3395 pragma(inline
, true)
3396 real log10(real x
) @safe pure nothrow @nogc
3398 version (INLINE_YL2X
)
3400 import std
.math
.constants
: LOG2
;
3401 return core
.math
.yl2x(x
, LOG2
);
3404 return log10Impl(x
);
3408 pragma(inline
, true)
3409 double log10(double x
) @safe pure nothrow @nogc { return __ctfe ?
cast(double) log10(cast(real) x
) : log10Impl(x
); }
3412 pragma(inline
, true)
3413 float log10(float x
) @safe pure nothrow @nogc { return __ctfe ?
cast(float) log10(cast(real) x
) : log10Impl(x
); }
3415 // @@@DEPRECATED_[2.112.0]@@@
3416 deprecated("`std.math.exponential.log10` called with argument types `(int)` matches both "
3417 ~ "`log10(real)`, `log10(double)`, and `log10(float)`. Cast argument to floating point type instead.")
3418 real log10(int x
) @safe pure nothrow @nogc { return log10(cast(real) x
); }
3419 // @@@DEPRECATED_[2.112.0]@@@
3420 deprecated("`std.math.exponential.log10` called with argument types `(uint)` matches both "
3421 ~ "`log10(real)`, `log10(double)`, and `log10(float)`. Cast argument to floating point type instead.")
3422 real log10(uint x
) @safe pure nothrow @nogc { return log10(cast(real) x
); }
3423 // @@@DEPRECATED_[2.112.0]@@@
3424 deprecated("`std.math.exponential.log10` called with argument types `(long)` matches both "
3425 ~ "`log10(real)`, `log10(double)`, and `log10(float)`. Cast argument to floating point type instead.")
3426 real log10(long x
) @safe pure nothrow @nogc { return log10(cast(real) x
); }
3427 // @@@DEPRECATED_[2.112.0]@@@
3428 deprecated("`std.math.exponential.log10` called with argument types `(ulong)` matches both "
3429 ~ "`log10(real)`, `log10(double)`, and `log10(float)`. Cast argument to floating point type instead.")
3430 real log10(ulong x
) @safe pure nothrow @nogc { return log10(cast(real) x
); }
3433 @safe pure nothrow @nogc unittest
3435 import std
.math
.algebraic
: fabs;
3437 assert(fabs(log10(1000.0L) - 3) < .000001);
3440 @safe pure nothrow @nogc unittest
3442 import std
.math
.algebraic
: fabs;
3444 assert(fabs(log10(1000.0) - 3) < .000001);
3445 assert(fabs(log10(1000.0f) - 3) < .000001);
3448 private T
log10Impl(T
)(T x
) @safe pure nothrow @nogc
3450 import std
.math
.constants
: SQRT1_2
;
3451 import std
.math
.algebraic
: poly
;
3452 import std
.math
.traits
: isNaN
, isInfinity
, signbit
;
3453 import std
.math
: floatTraits
, RealFormat
;
3455 alias coeffs
= LogCoeffs
!T
;
3456 alias F
= floatTraits
!T
;
3458 static if (F
.realFormat
== RealFormat
.ieeeExtended ||
3459 F
.realFormat
== RealFormat
.ieeeExtended53 ||
3460 F
.realFormat
== RealFormat
.ieeeQuadruple
)
3462 // log10(2) split into two parts.
3463 enum T L102A
= 0.3125L;
3464 enum T L102B
= -1.14700043360188047862611052755069732318101185E-2L;
3466 // log10(e) split into two parts.
3467 enum T L10EA
= 0.5L;
3468 enum T L10EB
= -6.570551809674817234887108108339491770560299E-2L;
3470 else static if (F
.realFormat
== RealFormat
.ieeeDouble ||
3471 F
.realFormat
== RealFormat
.ieeeSingle
)
3473 enum T L102A
= 3.0078125E-1;
3474 enum T L102B
= 2.48745663981195213739E-4;
3476 enum T L10EA
= 4.3359375E-1;
3477 enum T L10EB
= 7.00731903251827651129E-4;
3480 static assert(0, "Not implemented for this architecture");
3482 // Special cases are the same as for log.
3485 if (isInfinity(x
) && !signbit(x
))
3492 // Separate mantissa from exponent.
3493 // Note, frexp is used so that denormal numbers will be handled properly.
3499 static if (F
.realFormat
== RealFormat
.ieeeExtended ||
3500 F
.realFormat
== RealFormat
.ieeeExtended53 ||
3501 F
.realFormat
== RealFormat
.ieeeQuadruple
)
3503 // Logarithm using log(x) = z + z^^3 R(z) / S(z),
3504 // where z = 2(x - 1)/(x + 1)
3505 if ((exp
> 2) ||
(exp
< -2))
3508 { // 2(2x - 1)/(2x + 1)
3514 { // 2(x - 1)/(x + 1)
3521 y
= x
* (z
* poly(z
, coeffs
.logR
) / poly(z
, coeffs
.logS
));
3526 // Logarithm using log(1 + x) = x - .5x^^2 + x^^3 P(x) / Q(x)
3536 static if (F
.realFormat
== RealFormat
.ieeeSingle
)
3537 y
= x
* (z
* poly(x
, coeffs
.log10P
));
3539 y
= x
* (z
* poly(x
, coeffs
.log10P
) / poly(x
, coeffs
.log10Q
));
3542 // Multiply log of fraction by log10(e) and base 2 exponent by log10(2).
3543 // This sequence of operations is critical and it may be horribly
3544 // defeated by some compiler optimizers.
3556 @safe @nogc nothrow unittest
3558 import std
.math
: floatTraits
, RealFormat
;
3559 import std
.meta
: AliasSeq
;
3561 static void testLog10(T
)(T
[2][] vals
)
3563 import std
.math
.operations
: isClose
;
3564 import std
.math
.traits
: isNaN
;
3565 foreach (ref pair
; vals
)
3568 assert(isNaN(log10(pair
[0])));
3570 assert(isClose(log10(pair
[0]), pair
[1]));
3573 static foreach (F
; AliasSeq
!(float, double, real))
3576 [F(1), F(0x0p
+0)], [F(2), F(0x1.34413509f79fef
32p
-2)],
3577 [F(4), F(0x1.34413509f79fef
32p
-1)], [F(8), F(0x1.ce61cf8ef36fe6cap
-1)],
3578 [F(16), F(0x1.34413509f79fef
32p
+0)], [F(32), F(0x1.8151824c7587eafep
+0)],
3579 [F(64), F(0x1.ce61cf8ef36fe6cap
+0)], [F(128), F(0x1.0db90e
68b8abf
14cp
+1)],
3580 [F(256), F(0x1.34413509f79fef
32p
+1)], [F(512), F(0x1.5ac95bab3693ed18p
+1)],
3581 [F(1024), F(0x1.8151824c7587eafep
+1)], [F(2048), F(0x1.a7d9a8edb47be8e4p
+1)],
3582 [F(3), F(0x1.e8927964fd5fd08cp
-2)], [F(5), F(0x1.65df657b04300868p
-1)],
3583 [F(7), F(0x1.b0b0b0b78cc3f296p
-1)], [F(15), F(0x1.2d145116c
16ff856p
+0)],
3584 [F(17), F(0x1.3afeb354b7d9731ap
+0)], [F(31), F(0x1.7dc
9e
145867e
62eap
+0)],
3585 [F(33), F(0x1.84bd545e
4baeddp
+0)], [F(63), F(0x1.cca1950e4511e192p
+0)],
3586 [F(65), F(0x1.d01b16f9433cf7b8p
+0)], [F(-0), -F
.infinity
], [F(0), -F
.infinity
],
3587 [F(10000), F(0x1p
+2)],
3592 float[2][16] vals
= [
3593 [float.nan
, float.nan
],[-float.nan
, float.nan
],
3594 [float.infinity
, float.infinity
], [-float.infinity
, float.nan
],
3595 [float.min_normal
, -0x1.2f703p
+5f], [-float.min_normal
, float.nan
],
3596 [float.max
, 0x1.344136p
+5f], [-float.max
, float.nan
],
3597 [float.min_normal
/ 2, -0x1.31d8b2p
+5f], [-float.min_normal
/ 2, float.nan
],
3598 [float.max
/ 2, 0x1.31d8b2p
+5f], [-float.max
/ 2, float.nan
],
3599 [float.min_normal
/ 3, -0x1.334156p
+5f], [-float.min_normal
/ 3, float.nan
],
3600 [float.max
/ 3, 0x1.30701p
+5f], [-float.max
/ 3, float.nan
],
3605 double[2][16] vals
= [
3606 [double.nan
, double.nan
],[-double.nan
, double.nan
],
3607 [double.infinity
, double.infinity
], [-double.infinity
, double.nan
],
3608 [double.min_normal
, -0x1.33a7146f72a42p
+8], [-double.min_normal
, double.nan
],
3609 [double.max
, 0x1.34413509f79ffp
+8], [-double.max
, double.nan
],
3610 [double.min_normal
/ 2, -0x1.33f424bcb
522p
+8], [-double.min_normal
/ 2, double.nan
],
3611 [double.max
/ 2, 0x1.33f424bcb
522p
+8], [-double.max
/ 2, double.nan
],
3612 [double.min_normal
/ 3, -0x1.3421390dcbe
37p
+8], [-double.min_normal
/ 3, double.nan
],
3613 [double.max
/ 3, 0x1.33c7106b9e609p
+8], [-double.max
/ 3, double.nan
],
3617 alias F
= floatTraits
!real;
3618 static if (F
.realFormat
== RealFormat
.ieeeExtended || F
.realFormat
== RealFormat
.ieeeQuadruple
)
3620 real[2][16] vals
= [
3621 [real.nan
, real.nan
],[-real.nan
, real.nan
],
3622 [real.infinity
, real.infinity
], [-real.infinity
, real.nan
],
3623 [real.min_normal
, -0x1.343793004f503232p
+12L], [-real.min_normal
, real.nan
],
3624 [real.max
, 0x1.34413509f79fef
32p
+12L], [-real.max
, real.nan
],
3625 [real.min_normal
/ 2, -0x1.343c6405237810b2p
+12L], [-real.min_normal
/ 2, real.nan
],
3626 [real.max
/ 2, 0x1.343c6405237810b2p
+12L], [-real.max
/ 2, real.nan
],
3627 [real.min_normal
/ 3, -0x1.343f354a
34e
427bp
+12L], [-real.min_normal
/ 3, real.nan
],
3628 [real.max
/ 3, 0x1.343992c0120bf9b2p
+12L], [-real.max
/ 3, real.nan
],
3635 * Calculates the natural logarithm of 1 + x.
3637 * For very small x, log1p(x) will be more accurate than
3641 * $(TR $(TH x) $(TH log1p(x)) $(TH divide by 0?) $(TH invalid?))
3642 * $(TR $(TD $(PLUSMN)0.0) $(TD $(PLUSMN)0.0) $(TD no) $(TD no))
3643 * $(TR $(TD -1.0) $(TD -$(INFIN)) $(TD yes) $(TD no))
3644 * $(TR $(TD $(LT)-1.0) $(TD -$(NAN)) $(TD no) $(TD yes))
3645 * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) $(TD no) $(TD no))
3648 pragma(inline
, true)
3649 real log1p(real x
) @safe pure nothrow @nogc
3651 version (INLINE_YL2X
)
3653 // On x87, yl2xp1 is valid if and only if -0.5 <= lg(x) <= 0.5,
3654 // ie if -0.29 <= x <= 0.414
3655 import std
.math
.constants
: LN2
;
3656 return (core
.math
.fabs(x
) <= 0.25) ? core
.math
.yl2xp1(x
, LN2
) : core
.math
.yl2x(x
+1, LN2
);
3659 return log1pImpl(x
);
3663 pragma(inline
, true)
3664 double log1p(double x
) @safe pure nothrow @nogc { return __ctfe ?
cast(double) log1p(cast(real) x
) : log1pImpl(x
); }
3667 pragma(inline
, true)
3668 float log1p(float x
) @safe pure nothrow @nogc { return __ctfe ?
cast(float) log1p(cast(real) x
) : log1pImpl(x
); }
3670 // @@@DEPRECATED_[2.112.0]@@@
3671 deprecated("`std.math.exponential.log1p` called with argument types `(int)` matches both "
3672 ~ "`log1p(real)`, `log1p(double)`, and `log1p(float)`. Cast argument to floating point type instead.")
3673 real log1p(int x
) @safe pure nothrow @nogc { return log1p(cast(real) x
); }
3674 // @@@DEPRECATED_[2.112.0]@@@
3675 deprecated("`std.math.exponential.log1p` called with argument types `(uint)` matches both "
3676 ~ "`log1p(real)`, `log1p(double)`, and `log1p(float)`. Cast argument to floating point type instead.")
3677 real log1p(uint x
) @safe pure nothrow @nogc { return log1p(cast(real) x
); }
3678 // @@@DEPRECATED_[2.112.0]@@@
3679 deprecated("`std.math.exponential.log1p` called with argument types `(long)` matches both "
3680 ~ "`log1p(real)`, `log1p(double)`, and `log1p(float)`. Cast argument to floating point type instead.")
3681 real log1p(long x
) @safe pure nothrow @nogc { return log1p(cast(real) x
); }
3682 // @@@DEPRECATED_[2.112.0]@@@
3683 deprecated("`std.math.exponential.log1p` called with argument types `(ulong)` matches both "
3684 ~ "`log1p(real)`, `log1p(double)`, and `log1p(float)`. Cast argument to floating point type instead.")
3685 real log1p(ulong x
) @safe pure nothrow @nogc { return log1p(cast(real) x
); }
3690 import std
.math
.traits
: isIdentical
, isNaN
;
3691 import std
.math
.operations
: feqrel
;
3693 assert(isIdentical(log1p(0.0), 0.0));
3694 assert(log1p(1.0).feqrel(0.69314) > 16);
3696 assert(log1p(-1.0) == -real.infinity
);
3697 assert(isNaN(log1p(-2.0)));
3698 assert(log1p(real.nan
) is real.nan
);
3699 assert(log1p(-real.nan
) is -real.nan
);
3700 assert(log1p(real.infinity
) == real.infinity
);
3703 private T
log1pImpl(T
)(T x
) @safe pure nothrow @nogc
3705 import std
.math
.traits
: isNaN
, isInfinity
, signbit
;
3706 import std
.math
.algebraic
: poly
;
3707 import std
.math
.constants
: SQRT1_2
, SQRT2
;
3708 import std
.math
: floatTraits
, RealFormat
;
3711 if (isNaN(x
) || x
== 0.0)
3713 if (isInfinity(x
) && !signbit(x
))
3720 alias F
= floatTraits
!T
;
3721 static if (F
.realFormat
== RealFormat
.ieeeSingle ||
3722 F
.realFormat
== RealFormat
.ieeeDouble
)
3724 // When the input is within the range 1/sqrt(2) <= x+1 <= sqrt(2), compute
3725 // log1p inline. Forwarding to log() would otherwise result in inaccuracies.
3726 const T xp1
= x
+ 1.0;
3727 if (xp1
>= SQRT1_2
&& xp1
<= SQRT2
)
3729 alias coeffs
= LogCoeffs
!T
;
3731 T px
= poly(x
, coeffs
.logp1P
);
3732 T qx
= poly(x
, coeffs
.logp1Q
);
3734 qx
= x
+ ((cast(T
) -0.5) * xx
+ x
* (xx
* px
/ qx
));
3739 return logImpl
!(T
, true)(x
);
3742 @safe @nogc nothrow unittest
3744 import std
.math
: floatTraits
, RealFormat
;
3745 import std
.meta
: AliasSeq
;
3747 static void testLog1p(T
)(T
[2][] vals
)
3749 import std
.math
.operations
: isClose
;
3750 import std
.math
.traits
: isNaN
;
3751 foreach (ref pair
; vals
)
3754 assert(isNaN(log1p(pair
[0])));
3756 assert(isClose(log1p(pair
[0]), pair
[1]));
3759 static foreach (F
; AliasSeq
!(float, double, real))
3762 [F(1), F(0x1.62e42fefa39ef358p
-1)], [F(2), F(0x1.193ea7aad030a976p
+0)],
3763 [F(4), F(0x1.9c041f7ed8d336bp
+0)], [F(8), F(0x1.193ea7aad030a976p
+1)],
3764 [F(16), F(0x1.6aa6bc1fa7f79cfp
+1)], [F(32), F(0x1.bf8d8f4d5b8d1038p
+1)],
3765 [F(64), F(0x1.0b292939429755ap
+2)], [F(128), F(0x1.37072a9b5b6cb31p
+2)],
3766 [F(256), F(0x1.63241004e9010ad8p
+2)], [F(512), F(0x1.8f60adf
041bde
2a
8p
+2)],
3767 [F(1024), F(0x1.bbad39ebe1cc08b6p
+2)], [F(2048), F(0x1.e801c1698ba4395cp
+2)],
3768 [F(3), F(0x1.62e42fefa39ef358p
+0)], [F(5), F(0x1.cab0bfa2a2002322p
+0)],
3769 [F(7), F(0x1.0a2b23f3bab73682p
+1)], [F(15), F(0x1.62e42fefa39ef358p
+1)],
3770 [F(17), F(0x1.71f7b3a
6b918664cp
+1)], [F(31), F(0x1.bb9d3beb8c86b02ep
+1)],
3771 [F(33), F(0x1.c35fc81b90df59c6p
+1)], [F(63), F(0x1.0a2b23f3bab73682p
+2)],
3772 [F(65), F(0x1.0c234da4a23a6686p
+2)], [F(-0), F(-0x0p
+0)], [F(0), F(0x0p
+0)],
3773 [F(10000), F(0x1.26bbed
6fbd84182ep
+3)],
3778 float[2][16] vals
= [
3779 [float.nan
, float.nan
],[-float.nan
, float.nan
],
3780 [float.infinity
, float.infinity
], [-float.infinity
, float.nan
],
3781 [float.min_normal
, 0x1p
-126f], [-float.min_normal
, -0x1p
-126f],
3782 [float.max
, 0x1.62e43p
+6f], [-float.max
, float.nan
],
3783 [float.min_normal
/ 2, 0x0.8p
-126f], [-float.min_normal
/ 2, -0x0.8p
-126f],
3784 [float.max
/ 2, 0x1.601e68p
+6f], [-float.max
/ 2, float.nan
],
3785 [float.min_normal
/ 3, 0x0.555556p
-126f], [-float.min_normal
/ 3, -0x0.555556p
-126f],
3786 [float.max
/ 3, 0x1.5e7f36p
+6f], [-float.max
/ 3, float.nan
],
3791 double[2][16] vals
= [
3792 [double.nan
, double.nan
],[-double.nan
, double.nan
],
3793 [double.infinity
, double.infinity
], [-double.infinity
, double.nan
],
3794 [double.min_normal
, 0x1p
-1022], [-double.min_normal
, -0x1p
-1022],
3795 [double.max
, 0x1.62e42fefa39efp
+9], [-double.max
, double.nan
],
3796 [double.min_normal
/ 2, 0x0.8p
-1022], [-double.min_normal
/ 2, -0x0.8p
-1022],
3797 [double.max
/ 2, 0x1.628b76e
3a
7b61p
+9], [-double.max
/ 2, double.nan
],
3798 [double.min_normal
/ 3, 0x0.5555555555555p
-1022], [-double.min_normal
/ 3, -0x0.5555555555555p
-1022],
3799 [double.max
/ 3, 0x1.6257909bce
36ep
+9], [-double.max
/ 3, double.nan
],
3803 alias F
= floatTraits
!real;
3804 static if (F
.realFormat
== RealFormat
.ieeeExtended || F
.realFormat
== RealFormat
.ieeeQuadruple
)
3806 real[2][16] vals
= [
3807 [real.nan
, real.nan
],[-real.nan
, real.nan
],
3808 [real.infinity
, real.infinity
], [-real.infinity
, real.nan
],
3809 [real.min_normal
, 0x1p
-16382L], [-real.min_normal
, -0x1p
-16382L],
3810 [real.max
, 0x1.62e42fefa39ef358p
+13L], [-real.max
, real.nan
],
3811 [real.min_normal
/ 2, 0x0.8p
-16382L], [-real.min_normal
/ 2, -0x0.8p
-16382L],
3812 [real.max
/ 2, 0x1.62dea
45ee
3e
064dcp
+13L], [-real.max
/ 2, real.nan
],
3813 [real.min_normal
/ 3, 0x0.5555555555555556p
-16382L], [-real.min_normal
/ 3, -0x0.5555555555555556p
-16382L],
3814 [real.max
/ 3, 0x1.62db65fa
664871d2p
+13L], [-real.max
/ 3, real.nan
],
3820 /***************************************
3821 * Calculates the base-2 logarithm of x:
3825 * $(TR $(TH x) $(TH log2(x)) $(TH divide by 0?) $(TH invalid?))
3826 * $(TR $(TD $(PLUSMN)0.0) $(TD -$(INFIN)) $(TD yes) $(TD no) )
3827 * $(TR $(TD $(LT)0.0) $(TD $(NAN)) $(TD no) $(TD yes) )
3828 * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) $(TD no) $(TD no) )
3831 pragma(inline
, true)
3832 real log2(real x
) @safe pure nothrow @nogc
3834 version (INLINE_YL2X
)
3835 return core
.math
.yl2x(x
, 1.0L);
3841 pragma(inline
, true)
3842 double log2(double x
) @safe pure nothrow @nogc { return __ctfe ?
cast(double) log2(cast(real) x
) : log2Impl(x
); }
3845 pragma(inline
, true)
3846 float log2(float x
) @safe pure nothrow @nogc { return __ctfe ?
cast(float) log2(cast(real) x
) : log2Impl(x
); }
3848 // @@@DEPRECATED_[2.112.0]@@@
3849 deprecated("`std.math.exponential.log2` called with argument types `(int)` matches both "
3850 ~ "`log2(real)`, `log2(double)`, and `log2(float)`. Cast argument to floating point type instead.")
3851 real log2(int x
) @safe pure nothrow @nogc { return log2(cast(real) x
); }
3852 // @@@DEPRECATED_[2.112.0]@@@
3853 deprecated("`std.math.exponential.log2` called with argument types `(uint)` matches both "
3854 ~ "`log2(real)`, `log2(double)`, and `log2(float)`. Cast argument to floating point type instead.")
3855 real log2(uint x
) @safe pure nothrow @nogc { return log2(cast(real) x
); }
3856 // @@@DEPRECATED_[2.112.0]@@@
3857 deprecated("`std.math.exponential.log2` called with argument types `(long)` matches both "
3858 ~ "`log2(real)`, `log2(double)`, and `log2(float)`. Cast argument to floating point type instead.")
3859 real log2(long x
) @safe pure nothrow @nogc { return log2(cast(real) x
); }
3860 // @@@DEPRECATED_[2.112.0]@@@
3861 deprecated("`std.math.exponential.log2` called with argument types `(ulong)` matches both "
3862 ~ "`log2(real)`, `log2(double)`, and `log2(float)`. Cast argument to floating point type instead.")
3863 real log2(ulong x
) @safe pure nothrow @nogc { return log2(cast(real) x
); }
3868 import std
.math
.operations
: isClose
;
3870 assert(isClose(log2(1024.0L), 10));
3873 @safe @nogc nothrow unittest
3875 import std
.math
.operations
: isClose
;
3877 // check if values are equal to 19 decimal digits of precision
3878 assert(isClose(log2(1024.0L), 10, 1e-18));
3881 private T
log2Impl(T
)(T x
) @safe pure nothrow @nogc
3883 import std
.math
.traits
: isNaN
, isInfinity
, signbit
;
3884 import std
.math
.constants
: SQRT1_2
, LOG2E
;
3885 import std
.math
.algebraic
: poly
;
3886 import std
.math
: floatTraits
, RealFormat
;
3888 alias coeffs
= LogCoeffs
!T
;
3889 alias F
= floatTraits
!T
;
3891 // Special cases are the same as for log.
3894 if (isInfinity(x
) && !signbit(x
))
3901 // Separate mantissa from exponent.
3902 // Note, frexp is used so that denormal numbers will be handled properly.
3908 static if (F
.realFormat
== RealFormat
.ieeeDouble ||
3909 F
.realFormat
== RealFormat
.ieeeExtended ||
3910 F
.realFormat
== RealFormat
.ieeeExtended53 ||
3911 F
.realFormat
== RealFormat
.ieeeQuadruple
)
3913 // Logarithm using log(x) = z + z^^3 R(z) / S(z),
3914 // where z = 2(x - 1)/(x + 1)
3915 if ((exp
> 2) ||
(exp
< -2))
3918 { // 2(2x - 1)/(2x + 1)
3924 { // 2(x - 1)/(x + 1)
3931 y
= x
* (z
* poly(z
, coeffs
.logR
) / poly(z
, coeffs
.logS
));
3936 // Logarithm using log(1 + x) = x - .5x^^2 + x^^3 P(x) / Q(x)
3946 static if (F
.realFormat
== RealFormat
.ieeeSingle
)
3947 y
= x
* (z
* poly(x
, coeffs
.log2P
));
3949 y
= x
* (z
* poly(x
, coeffs
.log2P
) / poly(x
, coeffs
.log2Q
));
3952 // Multiply log of fraction by log10(e) and base 2 exponent by log10(2).
3953 // This sequence of operations is critical and it may be horribly
3954 // defeated by some compiler optimizers.
3956 z
= y
* (LOG2E
- 1.0);
3957 z
+= x
* (LOG2E
- 1.0);
3965 @safe @nogc nothrow unittest
3967 import std
.math
: floatTraits
, RealFormat
;
3968 import std
.meta
: AliasSeq
;
3970 static void testLog2(T
)(T
[2][] vals
)
3972 import std
.math
.operations
: isClose
;
3973 import std
.math
.traits
: isNaN
;
3974 foreach (ref pair
; vals
)
3977 assert(isNaN(log2(pair
[0])));
3979 assert(isClose(log2(pair
[0]), pair
[1]));
3982 static foreach (F
; AliasSeq
!(float, double, real))
3985 [F(1), F(0x0p
+0)], [F(2), F(0x1p
+0)],
3986 [F(4), F(0x1p
+1)], [F(8), F(0x1.8p
+1)],
3987 [F(16), F(0x1p
+2)], [F(32), F(0x1.4p
+2)],
3988 [F(64), F(0x1.8p
+2)], [F(128), F(0x1.cp
+2)],
3989 [F(256), F(0x1p
+3)], [F(512), F(0x1.2p
+3)],
3990 [F(1024), F(0x1.4p
+3)], [F(2048), F(0x1.6p
+3)],
3991 [F(3), F(0x1.95c01a39fbd687ap
+0)], [F(5), F(0x1.2934f0979a
3715fcp
+1)],
3992 [F(7), F(0x1.675767f54042cd
9ap
+1)], [F(15), F(0x1.f414fdb4982259ccp
+1)],
3993 [F(17), F(0x1.0598fdbeb
244c
5ap
+2)], [F(31), F(0x1.3d118d66c
4d4e
554p
+2)],
3994 [F(33), F(0x1.42d75a
6eb
1dfb0e
6p
+2)], [F(63), F(0x1.7e8bc1179e0caa9cp
+2)],
3995 [F(65), F(0x1.816e79685c2d2298p
+2)], [F(-0), -F
.infinity
], [F(0), -F
.infinity
],
3996 [F(10000), F(0x1.a934f0979a3715fcp
+3)],
4001 float[2][16] vals
= [
4002 [float.nan
, float.nan
],[-float.nan
, float.nan
],
4003 [float.infinity
, float.infinity
], [-float.infinity
, float.nan
],
4004 [float.min_normal
, -0x1.f8p
+6f], [-float.min_normal
, float.nan
],
4005 [float.max
, 0x1p
+7f], [-float.max
, float.nan
],
4006 [float.min_normal
/ 2, -0x1.fcp
+6f], [-float.min_normal
/ 2, float.nan
],
4007 [float.max
/ 2, 0x1.fcp
+6f], [-float.max
/ 2, float.nan
],
4008 [float.min_normal
/ 3, -0x1.fe57p
+6f], [-float.min_normal
/ 3, float.nan
],
4009 [float.max
/ 3, 0x1.f9a9p
+6f], [-float.max
/ 3, float.nan
],
4014 double[2][16] vals
= [
4015 [double.nan
, double.nan
],[-double.nan
, double.nan
],
4016 [double.infinity
, double.infinity
], [-double.infinity
, double.nan
],
4017 [double.min_normal
, -0x1.ffp
+9], [-double.min_normal
, double.nan
],
4018 [double.max
, 0x1p
+10], [-double.max
, double.nan
],
4019 [double.min_normal
/ 2, -0x1.ff8p
+9], [-double.min_normal
/ 2, double.nan
],
4020 [double.max
/ 2, 0x1.ff8p
+9], [-double.max
/ 2, double.nan
],
4021 [double.min_normal
/ 3, -0x1.ffcae00d1cfdfp
+9], [-double.min_normal
/ 3, double.nan
],
4022 [double.max
/ 3, 0x1.ff351ff2e3021p
+9], [-double.max
/ 3, double.nan
],
4026 alias F
= floatTraits
!real;
4027 static if (F
.realFormat
== RealFormat
.ieeeExtended || F
.realFormat
== RealFormat
.ieeeQuadruple
)
4029 real[2][16] vals
= [
4030 [real.nan
, real.nan
],[-real.nan
, real.nan
],
4031 [real.infinity
, real.infinity
], [-real.infinity
, real.nan
],
4032 [real.min_normal
, -0x1.fffp
+13L], [-real.min_normal
, real.nan
],
4033 [real.max
, 0x1p
+14L], [-real.max
, real.nan
],
4034 [real.min_normal
/ 2, -0x1.fff8p
+13L], [-real.min_normal
/ 2, real.nan
],
4035 [real.max
/ 2, 0x1.fff8p
+13L], [-real.max
/ 2, real.nan
],
4036 [real.min_normal
/ 3, -0x1.fffcae00d1cfdeb4p
+13L], [-real.min_normal
/ 3, real.nan
],
4037 [real.max
/ 3, 0x1.fff351ff2e30214cp
+13L], [-real.max
/ 3, real.nan
],
4043 /*****************************************
4044 * Extracts the exponent of x as a signed integral value.
4046 * If x is subnormal, it is treated as if it were normalized.
4047 * For a positive, finite x:
4049 * 1 $(LT)= $(I x) * FLT_RADIX$(SUPERSCRIPT -logb(x)) $(LT) FLT_RADIX
4052 * $(TR $(TH x) $(TH logb(x)) $(TH divide by 0?) )
4053 * $(TR $(TD $(PLUSMN)$(INFIN)) $(TD +$(INFIN)) $(TD no))
4054 * $(TR $(TD $(PLUSMN)0.0) $(TD -$(INFIN)) $(TD yes) )
4057 pragma(inline
, true)
4058 real logb(real x
) @trusted pure nothrow @nogc
4060 version (InlineAsm_X87_MSVC
)
4067 pragma(inline
, true)
4068 double logb(double x
) @trusted pure nothrow @nogc { return logbImpl(x
); }
4071 pragma(inline
, true)
4072 float logb(float x
) @trusted pure nothrow @nogc { return logbImpl(x
); }
4075 @safe @nogc nothrow unittest
4077 assert(logb(1.0) == 0);
4078 assert(logb(100.0) == 6);
4080 assert(logb(0.0) == -real.infinity
);
4081 assert(logb(real.infinity
) == real.infinity
);
4082 assert(logb(-real.infinity
) == real.infinity
);
4085 @safe @nogc nothrow unittest
4087 import std
.meta
: AliasSeq
;
4088 import std
.typecons
: Tuple
;
4089 import std
.math
.traits
: isNaN
;
4090 static foreach (F
; AliasSeq
!(float, double, real))
4092 alias T
= Tuple
!(F
, F
);
4093 T
[17] vals
= // x, logb(x)
4097 T(0.0 , -F
.infinity
),
4098 T(-0.0 , -F
.infinity
),
4101 T(0x0.1p
-127 , -131 ),
4102 T(0x0.01p
-127 , -135 ),
4103 T(0x0.011p
-127 , -135 ),
4106 T(F
.infinity
, F
.infinity
),
4107 T(-F
.infinity
, F
.infinity
),
4108 T(F
.min_normal
, F
.min_exp
-1),
4109 T(-F
.min_normal
, F
.min_exp
-1),
4110 T(F
.max
, F
.max_exp
-1),
4111 T(-F
.max
, F
.max_exp
-1),
4114 foreach (elem
; vals
)
4117 assert(isNaN(logb(elem
[1])));
4119 assert(logb(elem
[0]) == elem
[1]);
4124 version (InlineAsm_X87_MSVC
)
4125 private T
logbAsm(T
)(T x
) @trusted pure nothrow @nogc
4129 asm pure nothrow @nogc
4132 fld real ptr
[RCX
] ;
4140 asm pure nothrow @nogc
4149 private T
logbImpl(T
)(T x
) @trusted pure nothrow @nogc
4151 import std
.math
.traits
: isFinite
;
4153 // Handle special cases.
4157 return -1 / (x
* x
);
4162 @safe @nogc nothrow unittest
4164 import std
.math
: floatTraits
, RealFormat
;
4165 import std
.meta
: AliasSeq
;
4167 static void testLogb(T
)(T
[2][] vals
)
4169 import std
.math
.operations
: isClose
;
4170 import std
.math
.traits
: isNaN
;
4171 foreach (ref pair
; vals
)
4174 assert(isNaN(logb(pair
[0])));
4176 assert(isClose(logb(pair
[0]), pair
[1]));
4179 static foreach (F
; AliasSeq
!(float, double, real))
4182 [F(1), F(0x0p
+0)], [F(2), F(0x1p
+0)],
4183 [F(4), F(0x1p
+1)], [F(8), F(0x1.8p
+1)],
4184 [F(16), F(0x1p
+2)], [F(32), F(0x1.4p
+2)],
4185 [F(64), F(0x1.8p
+2)], [F(128), F(0x1.cp
+2)],
4186 [F(256), F(0x1p
+3)], [F(512), F(0x1.2p
+3)],
4187 [F(1024), F(0x1.4p
+3)], [F(2048), F(0x1.6p
+3)],
4188 [F(3), F(0x1p
+0)], [F(5), F(0x1p
+1)],
4189 [F(7), F(0x1p
+1)], [F(15), F(0x1.8p
+1)],
4190 [F(17), F(0x1p
+2)], [F(31), F(0x1p
+2)],
4191 [F(33), F(0x1.4p
+2)], [F(63), F(0x1.4p
+2)],
4192 [F(65), F(0x1.8p
+2)], [F(-0), -F
.infinity
], [F(0), -F
.infinity
],
4193 [F(10000), F(0x1.ap
+3)],
4198 float[2][16] vals
= [
4199 [float.nan
, float.nan
],[-float.nan
, float.nan
],
4200 [float.infinity
, float.infinity
], [-float.infinity
, float.infinity
],
4201 [float.min_normal
, -0x1.f8p
+6f], [-float.min_normal
, -0x1.f8p
+6f],
4202 [float.max
, 0x1.fcp
+6f], [-float.max
, 0x1.fcp
+6f],
4203 [float.min_normal
/ 2, -0x1.fcp
+6f], [-float.min_normal
/ 2, -0x1.fcp
+6f],
4204 [float.max
/ 2, 0x1.f8p
+6f], [-float.max
/ 2, 0x1.f8p
+6f],
4205 [float.min_normal
/ 3, -0x1p
+7f], [-float.min_normal
/ 3, -0x1p
+7f],
4206 [float.max
/ 3, 0x1.f8p
+6f], [-float.max
/ 3, 0x1.f8p
+6f],
4211 double[2][16] vals
= [
4212 [double.nan
, double.nan
],[-double.nan
, double.nan
],
4213 [double.infinity
, double.infinity
], [-double.infinity
, double.infinity
],
4214 [double.min_normal
, -0x1.ffp
+9], [-double.min_normal
, -0x1.ffp
+9],
4215 [double.max
, 0x1.ff8p
+9], [-double.max
, 0x1.ff8p
+9],
4216 [double.min_normal
/ 2, -0x1.ff8p
+9], [-double.min_normal
/ 2, -0x1.ff8p
+9],
4217 [double.max
/ 2, 0x1.ffp
+9], [-double.max
/ 2, 0x1.ffp
+9],
4218 [double.min_normal
/ 3, -0x1p
+10], [-double.min_normal
/ 3, -0x1p
+10],
4219 [double.max
/ 3, 0x1.ffp
+9], [-double.max
/ 3, 0x1.ffp
+9],
4223 alias F
= floatTraits
!real;
4224 static if (F
.realFormat
== RealFormat
.ieeeExtended || F
.realFormat
== RealFormat
.ieeeQuadruple
)
4226 real[2][16] vals
= [
4227 [real.nan
, real.nan
],[-real.nan
, real.nan
],
4228 [real.infinity
, real.infinity
], [-real.infinity
, real.infinity
],
4229 [real.min_normal
, -0x1.fffp
+13L], [-real.min_normal
, -0x1.fffp
+13L],
4230 [real.max
, 0x1.fff8p
+13L], [-real.max
, 0x1.fff8p
+13L],
4231 [real.min_normal
/ 2, -0x1.fff8p
+13L], [-real.min_normal
/ 2, -0x1.fff8p
+13L],
4232 [real.max
/ 2, 0x1.fffp
+13L], [-real.max
/ 2, 0x1.fffp
+13L],
4233 [real.min_normal
/ 3, -0x1p
+14L], [-real.min_normal
/ 3, -0x1p
+14L],
4234 [real.max
/ 3, 0x1.fffp
+13L], [-real.max
/ 3, 0x1.fffp
+13L],
4240 /*************************************
4241 * Efficiently calculates x * 2$(SUPERSCRIPT n).
4243 * scalbn handles underflow and overflow in
4244 * the same fashion as the basic arithmetic operators.
4247 * $(TR $(TH x) $(TH scalb(x)))
4248 * $(TR $(TD $(PLUSMNINF)) $(TD $(PLUSMNINF)) )
4249 * $(TR $(TD $(PLUSMN)0.0) $(TD $(PLUSMN)0.0) )
4252 pragma(inline
, true)
4253 real scalbn(real x
, int n
) @safe pure nothrow @nogc { return _scalbn(x
,n
); }
4256 pragma(inline
, true)
4257 double scalbn(double x
, int n
) @safe pure nothrow @nogc { return _scalbn(x
,n
); }
4260 pragma(inline
, true)
4261 float scalbn(float x
, int n
) @safe pure nothrow @nogc { return _scalbn(x
,n
); }
4264 @safe pure nothrow @nogc unittest
4266 assert(scalbn(0x1.2345678abcdefp0L
, 999) == 0x1.2345678abcdefp999L
);
4267 assert(scalbn(-real.infinity
, 5) == -real.infinity
);
4268 assert(scalbn(2.0,10) == 2048.0);
4269 assert(scalbn(2048.0f,-10) == 2.0f);
4272 pragma(inline
, true)
4273 private F
_scalbn(F
)(F x
, int n
)
4275 import std
.math
.traits
: isInfinity
;
4279 // Handle special cases.
4280 if (x
== F(0.0) ||
isInfinity(x
))
4283 return core
.math
.ldexp(x
, n
);
4286 @safe pure nothrow @nogc unittest
4289 static assert(scalbn(0x1.2345678abcdefp0L
, 999) == 0x1.2345678abcdefp999L
);
4290 static assert(scalbn(-real.infinity
, 5) == -real.infinity
);
4291 // Test with large exponent delta n where the result is in bounds but 2.0L ^^ n is not.
4292 enum initialExponent
= real.min_exp
+ 2, resultExponent
= real.max_exp
- 2;
4293 enum int n
= resultExponent
- initialExponent
;
4294 enum real x
= 0x1.2345678abcdefp0L
* (2.0L ^^ initialExponent
);
4295 enum staticResult
= scalbn(x
, n
);
4296 static assert(staticResult
== 0x1.2345678abcdefp0L
* (2.0L ^^ resultExponent
));
4297 assert(scalbn(x
, n
) == staticResult
);