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