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