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 {
version(all)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 */
isFinite(X)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 */
isNormal(X)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 */
isSubnormal(X)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 {
subnormalTest(T)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;
foo(T)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 */
isIdentical(real x,real y)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 */
signbit(X)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
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 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
foreach(x;[0.0L,3* min_sub,smallP7,0.1L,1337.0L,bigP7,X.max,real.nan,real.infinity])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 {{
foreach(x;[1,2,4,8,(X.max>>>1)+1])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
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 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
foreach(x;[0.0L,3* min_sub,smallP7,0.1L,1337.0L,bigP7,X.max,real.nan,real.infinity])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 {{
foreach(x;[1,2,4,8,(X.max>>>1)+1])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
854