1 // Written in the D programming language.
2 
3 /**
4 This is a submodule of $(MREF std, math).
5 
6 It contains several functions for introspection on numerical values.
7 
8 Copyright: Copyright The D Language Foundation 2000 - 2011.
9 License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
10 Authors:   $(HTTP digitalmars.com, Walter Bright), Don Clugston,
11            Conversion of CEPHES math library to D by Iain Buclaw and David Nadlinger
12 Source: $(PHOBOSSRC std/math/traits.d)
13 
14 Macros:
15     NAN = $(RED NAN)
16     PLUSMN = ±
17     INFIN = ∞
18  */
19 
20 module std.math.traits;
21 
22 import std.traits : isFloatingPoint, isIntegral, isNumeric, isSigned;
23 
24 /*********************************
25  * Determines if $(D_PARAM x) is NaN.
26  * Params:
27  *  x = a floating point number.
28  * Returns:
29  *  `true` if $(D_PARAM x) is Nan.
30  */
31 bool isNaN(X)(X x) @nogc @trusted pure nothrow
32 if (isFloatingPoint!(X))
33 {
34     version (all)
35     {
36         return x != x;
37     }
38     else
39     {
40         /*
41         Code kept for historical context. At least on Intel, the simple test
42         x != x uses one dedicated instruction (ucomiss/ucomisd) that runs in one
43         cycle. Code for 80- and 128-bits is larger but still smaller than the
44         integrals-based solutions below. Future revisions may enable the code
45         below conditionally depending on hardware.
46         */
47         alias F = floatTraits!(X);
48         static if (F.realFormat == RealFormat.ieeeSingle)
49         {
50             const uint p = *cast(uint *)&x;
51             // Sign bit (MSB) is irrelevant so mask it out.
52             // Next 8 bits should be all set.
53             // At least one bit among the least significant 23 bits should be set.
54             return (p & 0x7FFF_FFFF) > 0x7F80_0000;
55         }
56         else static if (F.realFormat == RealFormat.ieeeDouble)
57         {
58             const ulong  p = *cast(ulong *)&x;
59             // Sign bit (MSB) is irrelevant so mask it out.
60             // Next 11 bits should be all set.
61             // At least one bit among the least significant 52 bits should be set.
62             return (p & 0x7FFF_FFFF_FFFF_FFFF) > 0x7FF0_0000_0000_0000;
63         }
64         else static if (F.realFormat == RealFormat.ieeeExtended ||
65                         F.realFormat == RealFormat.ieeeExtended53)
66         {
67             const ushort e = F.EXPMASK & (cast(ushort *)&x)[F.EXPPOS_SHORT];
68             const ulong ps = *cast(ulong *)&x;
69             return e == F.EXPMASK &&
70                 ps & 0x7FFF_FFFF_FFFF_FFFF; // not infinity
71         }
72         else static if (F.realFormat == RealFormat.ieeeQuadruple)
73         {
74             const ushort e = F.EXPMASK & (cast(ushort *)&x)[F.EXPPOS_SHORT];
75             const ulong psLsb = (cast(ulong *)&x)[MANTISSA_LSB];
76             const ulong psMsb = (cast(ulong *)&x)[MANTISSA_MSB];
77             return e == F.EXPMASK &&
78                 (psLsb | (psMsb& 0x0000_FFFF_FFFF_FFFF)) != 0;
79         }
80         else
81         {
82             return x != x;
83         }
84     }
85 }
86 
87 ///
88 @safe pure nothrow @nogc unittest
89 {
90     assert( isNaN(float.init));
91     assert( isNaN(-double.init));
92     assert( isNaN(real.nan));
93     assert( isNaN(-real.nan));
94     assert(!isNaN(cast(float) 53.6));
95     assert(!isNaN(cast(real)-53.6));
96 }
97 
98 @safe pure nothrow @nogc unittest
99 {
100     import std.meta : AliasSeq;
101 
102     static foreach (T; AliasSeq!(float, double, real))
103     {{
104         // CTFE-able tests
105         assert(isNaN(T.init));
106         assert(isNaN(-T.init));
107         assert(isNaN(T.nan));
108         assert(isNaN(-T.nan));
109         assert(!isNaN(T.infinity));
110         assert(!isNaN(-T.infinity));
111         assert(!isNaN(cast(T) 53.6));
112         assert(!isNaN(cast(T)-53.6));
113 
114         // Runtime tests
115         shared T f;
116         f = T.init;
117         assert(isNaN(f));
118         assert(isNaN(-f));
119         f = T.nan;
120         assert(isNaN(f));
121         assert(isNaN(-f));
122         f = T.infinity;
123         assert(!isNaN(f));
124         assert(!isNaN(-f));
125         f = cast(T) 53.6;
126         assert(!isNaN(f));
127         assert(!isNaN(-f));
128     }}
129 }
130 
131 /*********************************
132  * Determines if $(D_PARAM x) is finite.
133  * Params:
134  *  x = a floating point number.
135  * Returns:
136  *  `true` if $(D_PARAM x) is finite.
137  */
138 bool isFinite(X)(X x) @trusted pure nothrow @nogc
139 {
140     import std.math : floatTraits, RealFormat;
141 
142     static if (__traits(isFloating, X))
143         if (__ctfe)
144             return x == x && x != X.infinity && x != -X.infinity;
145     alias F = floatTraits!(X);
146     ushort* pe = cast(ushort *)&x;
147     return (pe[F.EXPPOS_SHORT] & F.EXPMASK) != F.EXPMASK;
148 }
149 
150 ///
151 @safe pure nothrow @nogc unittest
152 {
153     assert( isFinite(1.23f));
154     assert( isFinite(float.max));
155     assert( isFinite(float.min_normal));
156     assert(!isFinite(float.nan));
157     assert(!isFinite(float.infinity));
158 }
159 
160 @safe pure nothrow @nogc unittest
161 {
162     assert(isFinite(1.23));
163     assert(isFinite(double.max));
164     assert(isFinite(double.min_normal));
165     assert(!isFinite(double.nan));
166     assert(!isFinite(double.infinity));
167 
168     assert(isFinite(1.23L));
169     assert(isFinite(real.max));
170     assert(isFinite(real.min_normal));
171     assert(!isFinite(real.nan));
172     assert(!isFinite(real.infinity));
173 
174     //CTFE
175     static assert(isFinite(1.23));
176     static assert(isFinite(double.max));
177     static assert(isFinite(double.min_normal));
178     static assert(!isFinite(double.nan));
179     static assert(!isFinite(double.infinity));
180 
181     static assert(isFinite(1.23L));
182     static assert(isFinite(real.max));
183     static assert(isFinite(real.min_normal));
184     static assert(!isFinite(real.nan));
185     static assert(!isFinite(real.infinity));
186 }
187 
188 
189 /*********************************
190  * Determines if $(D_PARAM x) is normalized.
191  *
192  * A normalized number must not be zero, subnormal, infinite nor $(NAN).
193  *
194  * Params:
195  *  x = a floating point number.
196  * Returns:
197  *  `true` if $(D_PARAM x) is normalized.
198  */
199 
200 /* Need one for each format because subnormal floats might
201  * be converted to normal reals.
202  */
203 bool isNormal(X)(X x) @trusted pure nothrow @nogc
204 {
205     import std.math : floatTraits, RealFormat;
206 
207     static if (__traits(isFloating, X))
208         if (__ctfe)
209             return (x <= -X.min_normal && x != -X.infinity) || (x >= X.min_normal && x != X.infinity);
210     alias F = floatTraits!(X);
211     ushort e = F.EXPMASK & (cast(ushort *)&x)[F.EXPPOS_SHORT];
212     return (e != F.EXPMASK && e != 0);
213 }
214 
215 ///
216 @safe pure nothrow @nogc unittest
217 {
218     float f = 3;
219     double d = 500;
220     real e = 10e+48;
221 
222     assert(isNormal(f));
223     assert(isNormal(d));
224     assert(isNormal(e));
225     f = d = e = 0;
226     assert(!isNormal(f));
227     assert(!isNormal(d));
228     assert(!isNormal(e));
229     assert(!isNormal(real.infinity));
230     assert(isNormal(-real.max));
231     assert(!isNormal(real.min_normal/4));
232 
233 }
234 
235 @safe pure nothrow @nogc unittest
236 {
237     // CTFE
238     enum float f = 3;
239     enum double d = 500;
240     enum real e = 10e+48;
241 
242     static assert(isNormal(f));
243     static assert(isNormal(d));
244     static assert(isNormal(e));
245 
246     static assert(!isNormal(0.0f));
247     static assert(!isNormal(0.0));
248     static assert(!isNormal(0.0L));
249     static assert(!isNormal(real.infinity));
250     static assert(isNormal(-real.max));
251     static assert(!isNormal(real.min_normal/4));
252 }
253 
254 /*********************************
255  * Determines if $(D_PARAM x) is subnormal.
256  *
257  * Subnormals (also known as "denormal number"), have a 0 exponent
258  * and a 0 most significant mantissa bit.
259  *
260  * Params:
261  *  x = a floating point number.
262  * Returns:
263  *  `true` if $(D_PARAM x) is a denormal number.
264  */
265 bool isSubnormal(X)(X x) @trusted pure nothrow @nogc
266 {
267     import std.math : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB;
268 
269     static if (__traits(isFloating, X))
270         if (__ctfe)
271             return -X.min_normal < x && x < X.min_normal;
272     /*
273         Need one for each format because subnormal floats might
274         be converted to normal reals.
275     */
276     alias F = floatTraits!(X);
277     static if (F.realFormat == RealFormat.ieeeSingle)
278     {
279         uint *p = cast(uint *)&x;
280         return (*p & F.EXPMASK_INT) == 0 && *p & F.MANTISSAMASK_INT;
281     }
282     else static if (F.realFormat == RealFormat.ieeeDouble)
283     {
284         uint *p = cast(uint *)&x;
285         return (p[MANTISSA_MSB] & F.EXPMASK_INT) == 0
286             && (p[MANTISSA_LSB] || p[MANTISSA_MSB] & F.MANTISSAMASK_INT);
287     }
288     else static if (F.realFormat == RealFormat.ieeeQuadruple)
289     {
290         ushort e = F.EXPMASK & (cast(ushort *)&x)[F.EXPPOS_SHORT];
291         long*   ps = cast(long *)&x;
292         return (e == 0 &&
293           ((ps[MANTISSA_LSB]|(ps[MANTISSA_MSB]& 0x0000_FFFF_FFFF_FFFF)) != 0));
294     }
295     else static if (F.realFormat == RealFormat.ieeeExtended ||
296                     F.realFormat == RealFormat.ieeeExtended53)
297     {
298         ushort* pe = cast(ushort *)&x;
299         long*   ps = cast(long *)&x;
300 
301         return (pe[F.EXPPOS_SHORT] & F.EXPMASK) == 0 && *ps > 0;
302     }
303     else
304     {
305         static assert(false, "Not implemented for this architecture");
306     }
307 }
308 
309 ///
310 @safe pure nothrow @nogc unittest
311 {
312     import std.meta : AliasSeq;
313 
314     static foreach (T; AliasSeq!(float, double, real))
315     {{
316         T f;
317         for (f = 1.0; !isSubnormal(f); f /= 2)
318             assert(f != 0);
319     }}
320 }
321 
322 @safe pure nothrow @nogc unittest
323 {
324     static bool subnormalTest(T)()
325     {
326         T f;
327         for (f = 1.0; !isSubnormal(f); f /= 2)
328             if (f == 0)
329                 return false;
330         return true;
331     }
332     static assert(subnormalTest!float());
333     static assert(subnormalTest!double());
334     static assert(subnormalTest!real());
335 }
336 
337 /*********************************
338  * Determines if $(D_PARAM x) is $(PLUSMN)$(INFIN).
339  * Params:
340  *  x = a floating point number.
341  * Returns:
342  *  `true` if $(D_PARAM x) is $(PLUSMN)$(INFIN).
343  */
344 bool isInfinity(X)(X x) @nogc @trusted pure nothrow
345 if (isFloatingPoint!(X))
346 {
347     import std.math : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB;
348 
349     alias F = floatTraits!(X);
350     static if (F.realFormat == RealFormat.ieeeSingle)
351     {
352         return ((*cast(uint *)&x) & 0x7FFF_FFFF) == 0x7F80_0000;
353     }
354     else static if (F.realFormat == RealFormat.ieeeDouble)
355     {
356         return ((*cast(ulong *)&x) & 0x7FFF_FFFF_FFFF_FFFF)
357             == 0x7FF0_0000_0000_0000;
358     }
359     else static if (F.realFormat == RealFormat.ieeeExtended ||
360                     F.realFormat == RealFormat.ieeeExtended53)
361     {
362         const ushort e = cast(ushort)(F.EXPMASK & (cast(ushort *)&x)[F.EXPPOS_SHORT]);
363         const ulong ps = *cast(ulong *)&x;
364 
365         // On Motorola 68K, infinity can have hidden bit = 1 or 0. On x86, it is always 1.
366         return e == F.EXPMASK && (ps & 0x7FFF_FFFF_FFFF_FFFF) == 0;
367     }
368     else static if (F.realFormat == RealFormat.ieeeQuadruple)
369     {
370         const long psLsb = (cast(long *)&x)[MANTISSA_LSB];
371         const long psMsb = (cast(long *)&x)[MANTISSA_MSB];
372         return (psLsb == 0)
373             && (psMsb & 0x7FFF_FFFF_FFFF_FFFF) == 0x7FFF_0000_0000_0000;
374     }
375     else
376     {
377         return (x < -X.max) || (X.max < x);
378     }
379 }
380 
381 ///
382 @nogc @safe pure nothrow unittest
383 {
384     assert(!isInfinity(float.init));
385     assert(!isInfinity(-float.init));
386     assert(!isInfinity(float.nan));
387     assert(!isInfinity(-float.nan));
388     assert(isInfinity(float.infinity));
389     assert(isInfinity(-float.infinity));
390     assert(isInfinity(-1.0f / 0.0f));
391 }
392 
393 @safe pure nothrow @nogc unittest
394 {
395     // CTFE-able tests
396     assert(!isInfinity(double.init));
397     assert(!isInfinity(-double.init));
398     assert(!isInfinity(double.nan));
399     assert(!isInfinity(-double.nan));
400     assert(isInfinity(double.infinity));
401     assert(isInfinity(-double.infinity));
402     assert(isInfinity(-1.0 / 0.0));
403 
404     assert(!isInfinity(real.init));
405     assert(!isInfinity(-real.init));
406     assert(!isInfinity(real.nan));
407     assert(!isInfinity(-real.nan));
408     assert(isInfinity(real.infinity));
409     assert(isInfinity(-real.infinity));
410     assert(isInfinity(-1.0L / 0.0L));
411 
412     // Runtime tests
413     shared float f;
414     f = float.init;
415     assert(!isInfinity(f));
416     assert(!isInfinity(-f));
417     f = float.nan;
418     assert(!isInfinity(f));
419     assert(!isInfinity(-f));
420     f = float.infinity;
421     assert(isInfinity(f));
422     assert(isInfinity(-f));
423     f = (-1.0f / 0.0f);
424     assert(isInfinity(f));
425 
426     shared double d;
427     d = double.init;
428     assert(!isInfinity(d));
429     assert(!isInfinity(-d));
430     d = double.nan;
431     assert(!isInfinity(d));
432     assert(!isInfinity(-d));
433     d = double.infinity;
434     assert(isInfinity(d));
435     assert(isInfinity(-d));
436     d = (-1.0 / 0.0);
437     assert(isInfinity(d));
438 
439     shared real e;
440     e = real.init;
441     assert(!isInfinity(e));
442     assert(!isInfinity(-e));
443     e = real.nan;
444     assert(!isInfinity(e));
445     assert(!isInfinity(-e));
446     e = real.infinity;
447     assert(isInfinity(e));
448     assert(isInfinity(-e));
449     e = (-1.0L / 0.0L);
450     assert(isInfinity(e));
451 }
452 
453 @nogc @safe pure nothrow unittest
454 {
455     import std.meta : AliasSeq;
456     static bool foo(T)(inout T x) { return isInfinity(x); }
457     foreach (T; AliasSeq!(float, double, real))
458     {
459         assert(!foo(T(3.14f)));
460         assert(foo(T.infinity));
461     }
462 }
463 
464 /*********************************
465  * Is the binary representation of x identical to y?
466  */
467 bool isIdentical(real x, real y) @trusted pure nothrow @nogc
468 {
469     import std.math : floatTraits, RealFormat;
470 
471     // We're doing a bitwise comparison so the endianness is irrelevant.
472     long*   pxs = cast(long *)&x;
473     long*   pys = cast(long *)&y;
474     alias F = floatTraits!(real);
475     static if (F.realFormat == RealFormat.ieeeDouble)
476     {
477         return pxs[0] == pys[0];
478     }
479     else static if (F.realFormat == RealFormat.ieeeQuadruple)
480     {
481         return pxs[0] == pys[0] && pxs[1] == pys[1];
482     }
483     else static if (F.realFormat == RealFormat.ieeeExtended)
484     {
485         ushort* pxe = cast(ushort *)&x;
486         ushort* pye = cast(ushort *)&y;
487         return pxe[4] == pye[4] && pxs[0] == pys[0];
488     }
489     else
490     {
491         assert(0, "isIdentical not implemented");
492     }
493 }
494 
495 ///
496 @safe @nogc pure nothrow unittest
497 {
498     assert( isIdentical(0.0, 0.0));
499     assert( isIdentical(1.0, 1.0));
500     assert( isIdentical(real.infinity, real.infinity));
501     assert( isIdentical(-real.infinity, -real.infinity));
502 
503     assert(!isIdentical(0.0, -0.0));
504     assert(!isIdentical(real.nan, -real.nan));
505     assert(!isIdentical(real.infinity, -real.infinity));
506 }
507 
508 /*********************************
509  * Return 1 if sign bit of e is set, 0 if not.
510  */
511 int signbit(X)(X x) @nogc @trusted pure nothrow
512 {
513     import std.math : floatTraits, RealFormat;
514 
515     if (__ctfe)
516     {
517         double dval = cast(double) x; // Precision can increase or decrease but sign won't change (even NaN).
518         return 0 > *cast(long*) &dval;
519     }
520 
521     alias F = floatTraits!(X);
522     return ((cast(ubyte *)&x)[F.SIGNPOS_BYTE] & 0x80) != 0;
523 }
524 
525 ///
526 @nogc @safe pure nothrow unittest
527 {
528     assert(!signbit(float.nan));
529     assert(signbit(-float.nan));
530     assert(!signbit(168.1234f));
531     assert(signbit(-168.1234f));
532     assert(!signbit(0.0f));
533     assert(signbit(-0.0f));
534     assert(signbit(-float.max));
535     assert(!signbit(float.max));
536 
537     assert(!signbit(double.nan));
538     assert(signbit(-double.nan));
539     assert(!signbit(168.1234));
540     assert(signbit(-168.1234));
541     assert(!signbit(0.0));
542     assert(signbit(-0.0));
543     assert(signbit(-double.max));
544     assert(!signbit(double.max));
545 
546     assert(!signbit(real.nan));
547     assert(signbit(-real.nan));
548     assert(!signbit(168.1234L));
549     assert(signbit(-168.1234L));
550     assert(!signbit(0.0L));
551     assert(signbit(-0.0L));
552     assert(signbit(-real.max));
553     assert(!signbit(real.max));
554 }
555 
556 @nogc @safe pure nothrow unittest
557 {
558     // CTFE
559     static assert(!signbit(float.nan));
560     static assert(signbit(-float.nan));
561     static assert(!signbit(168.1234f));
562     static assert(signbit(-168.1234f));
563     static assert(!signbit(0.0f));
564     static assert(signbit(-0.0f));
565     static assert(signbit(-float.max));
566     static assert(!signbit(float.max));
567 
568     static assert(!signbit(double.nan));
569     static assert(signbit(-double.nan));
570     static assert(!signbit(168.1234));
571     static assert(signbit(-168.1234));
572     static assert(!signbit(0.0));
573     static assert(signbit(-0.0));
574     static assert(signbit(-double.max));
575     static assert(!signbit(double.max));
576 
577     static assert(!signbit(real.nan));
578     static assert(signbit(-real.nan));
579     static assert(!signbit(168.1234L));
580     static assert(signbit(-168.1234L));
581     static assert(!signbit(0.0L));
582     static assert(signbit(-0.0L));
583     static assert(signbit(-real.max));
584     static assert(!signbit(real.max));
585 }
586 
587 /**
588 Params:
589     to = the numeric value to use
590     from = the sign value to use
591 Returns:
592     a value composed of to with from's sign bit.
593  */
594 R copysign(R, X)(R to, X from) @trusted pure nothrow @nogc
595 if (isFloatingPoint!(R) && isFloatingPoint!(X))
596 {
597     import std.math : floatTraits, RealFormat;
598 
599     if (__ctfe)
600     {
601         return signbit(to) == signbit(from) ? to : -to;
602     }
603     ubyte* pto   = cast(ubyte *)&to;
604     const ubyte* pfrom = cast(ubyte *)&from;
605 
606     alias T = floatTraits!(R);
607     alias F = floatTraits!(X);
608     pto[T.SIGNPOS_BYTE] &= 0x7F;
609     pto[T.SIGNPOS_BYTE] |= pfrom[F.SIGNPOS_BYTE] & 0x80;
610     return to;
611 }
612 
613 /// ditto
614 R copysign(R, X)(X to, R from) @trusted pure nothrow @nogc
615 if (isIntegral!(X) && isFloatingPoint!(R))
616 {
617     return copysign(cast(R) to, from);
618 }
619 
620 ///
621 @safe pure nothrow @nogc unittest
622 {
623     assert(copysign(1.0, 1.0) == 1.0);
624     assert(copysign(1.0, -0.0) == -1.0);
625     assert(copysign(1UL, -1.0) == -1.0);
626     assert(copysign(-1.0, -1.0) == -1.0);
627 
628     assert(copysign(real.infinity, -1.0) == -real.infinity);
629     assert(copysign(real.nan, 1.0) is real.nan);
630     assert(copysign(-real.nan, 1.0) is real.nan);
631     assert(copysign(real.nan, -1.0) is -real.nan);
632 }
633 
634 @safe pure nothrow @nogc unittest
635 {
636     import std.meta : AliasSeq;
637 
638     static foreach (X; AliasSeq!(float, double, real, int, long))
639     {
640         static foreach (Y; AliasSeq!(float, double, real))
641         {{
642             X x = 21;
643             Y y = 23.8;
644             Y e = void;
645 
646             e = copysign(x, y);
647             assert(e == 21.0);
648 
649             e = copysign(-x, y);
650             assert(e == 21.0);
651 
652             e = copysign(x, -y);
653             assert(e == -21.0);
654 
655             e = copysign(-x, -y);
656             assert(e == -21.0);
657 
658             static if (isFloatingPoint!X)
659             {
660                 e = copysign(X.nan, y);
661                 assert(isNaN(e) && !signbit(e));
662 
663                 e = copysign(X.nan, -y);
664                 assert(isNaN(e) && signbit(e));
665             }
666         }}
667     }
668     // CTFE
669     static foreach (X; AliasSeq!(float, double, real, int, long))
670     {
671         static foreach (Y; AliasSeq!(float, double, real))
672         {{
673             enum X x = 21;
674             enum Y y = 23.8;
675 
676             assert(21.0 == copysign(x, y));
677             assert(21.0 == copysign(-x, y));
678             assert(-21.0 == copysign(x, -y));
679             assert(-21.0 == copysign(-x, -y));
680 
681             static if (isFloatingPoint!X)
682             {
683                 static assert(isNaN(copysign(X.nan, y)) && !signbit(copysign(X.nan, y)));
684                 assert(isNaN(copysign(X.nan, -y)) && signbit(copysign(X.nan, -y)));
685             }
686         }}
687     }
688 }
689 
690 /*********************************
691 Returns `-1` if $(D x < 0), `x` if $(D x == 0), `1` if
692 $(D x > 0), and $(NAN) if x==$(NAN).
693  */
694 F sgn(F)(F x) @safe pure nothrow @nogc
695 if (isFloatingPoint!F || isIntegral!F)
696 {
697     // @@@TODO@@@: make this faster
698     return x > 0 ? 1 : x < 0 ? -1 : x;
699 }
700 
701 ///
702 @safe pure nothrow @nogc unittest
703 {
704     assert(sgn(168.1234) == 1);
705     assert(sgn(-168.1234) == -1);
706     assert(sgn(0.0) == 0);
707     assert(sgn(-0.0) == 0);
708 }
709 
710 /**
711 Check whether a number is an integer power of two.
712 
713 Note that only positive numbers can be integer powers of two. This
714 function always return `false` if `x` is negative or zero.
715 
716 Params:
717     x = the number to test
718 
719 Returns:
720     `true` if `x` is an integer power of two.
721 */
722 bool isPowerOf2(X)(const X x) pure @safe nothrow @nogc
723 if (isNumeric!X)
724 {
725     import std.math.exponential : frexp;
726 
727     static if (isFloatingPoint!X)
728     {
729         int exp;
730         const X sig = frexp(x, exp);
731 
732         return (exp != int.min) && (sig is cast(X) 0.5L);
733     }
734     else
735     {
736         static if (isSigned!X)
737         {
738             auto y = cast(typeof(x + 0))x;
739             return y > 0 && !(y & (y - 1));
740         }
741         else
742         {
743             auto y = cast(typeof(x + 0u))x;
744             return (y & -y) > (y - 1);
745         }
746     }
747 }
748 ///
749 @safe unittest
750 {
751     import std.math.exponential : pow;
752 
753     assert( isPowerOf2(1.0L));
754     assert( isPowerOf2(2.0L));
755     assert( isPowerOf2(0.5L));
756     assert( isPowerOf2(pow(2.0L, 96)));
757     assert( isPowerOf2(pow(2.0L, -77)));
758 
759     assert(!isPowerOf2(-2.0L));
760     assert(!isPowerOf2(-0.5L));
761     assert(!isPowerOf2(0.0L));
762     assert(!isPowerOf2(4.315));
763     assert(!isPowerOf2(1.0L / 3.0L));
764 
765     assert(!isPowerOf2(real.nan));
766     assert(!isPowerOf2(real.infinity));
767 }
768 ///
769 @safe unittest
770 {
771     assert( isPowerOf2(1));
772     assert( isPowerOf2(2));
773     assert( isPowerOf2(1uL << 63));
774 
775     assert(!isPowerOf2(-4));
776     assert(!isPowerOf2(0));
777     assert(!isPowerOf2(1337u));
778 }
779 
780 @safe unittest
781 {
782     import std.math.exponential : pow;
783     import std.meta : AliasSeq;
784 
785     enum smallP2 = pow(2.0L, -62);
786     enum bigP2 = pow(2.0L, 50);
787     enum smallP7 = pow(7.0L, -35);
788     enum bigP7 = pow(7.0L, 30);
789 
790     static foreach (X; AliasSeq!(float, double, real))
791     {{
792         immutable min_sub = X.min_normal * X.epsilon;
793 
794         foreach (x; [smallP2, min_sub, X.min_normal, .25L, 0.5L, 1.0L,
795                               2.0L, 8.0L, pow(2.0L, X.max_exp - 1), bigP2])
796         {
797             assert( isPowerOf2(cast(X) x));
798             assert(!isPowerOf2(cast(X)-x));
799         }
800 
801         foreach (x; [0.0L, 3 * min_sub, smallP7, 0.1L, 1337.0L, bigP7, X.max, real.nan, real.infinity])
802         {
803             assert(!isPowerOf2(cast(X) x));
804             assert(!isPowerOf2(cast(X)-x));
805         }
806     }}
807 
808     static foreach (X; AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong))
809     {{
810         foreach (x; [1, 2, 4, 8, (X.max >>> 1) + 1])
811         {
812             assert( isPowerOf2(cast(X) x));
813             static if (isSigned!X)
814                 assert(!isPowerOf2(cast(X)-x));
815         }
816 
817         foreach (x; [0, 3, 5, 13, 77, X.min, X.max])
818             assert(!isPowerOf2(cast(X) x));
819     }}
820 
821     // CTFE
822     static foreach (X; AliasSeq!(float, double, real))
823     {{
824         enum min_sub = X.min_normal * X.epsilon;
825 
826         static foreach (x; [smallP2, min_sub, X.min_normal, .25L, 0.5L, 1.0L,
827                               2.0L, 8.0L, pow(2.0L, X.max_exp - 1), bigP2])
828         {
829             static assert( isPowerOf2(cast(X) x));
830             static assert(!isPowerOf2(cast(X)-x));
831         }
832 
833         static foreach (x; [0.0L, 3 * min_sub, smallP7, 0.1L, 1337.0L, bigP7, X.max, real.nan, real.infinity])
834         {
835             static assert(!isPowerOf2(cast(X) x));
836             static assert(!isPowerOf2(cast(X)-x));
837         }
838     }}
839 
840     static foreach (X; AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong))
841     {{
842         static foreach (x; [1, 2, 4, 8, (X.max >>> 1) + 1])
843         {
844             static assert( isPowerOf2(cast(X) x));
845             static if (isSigned!X)
846                 static assert(!isPowerOf2(cast(X)-x));
847         }
848 
849         static foreach (x; [0, 3, 5, 13, 77, X.min, X.max])
850             static assert(!isPowerOf2(cast(X) x));
851     }}
852 }
853