The OpenD Programming Language

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