1 // Written in the D programming language.
4 This is a submodule of $(MREF std, math).
6 It contains several functions for introspection on numerical values.
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)
20 module std
.math
.traits
;
22 import std
.traits
: isFloatingPoint
, isIntegral
, isNumeric
, isSigned
;
25 /*********************************
26 * Determines if $(D_PARAM x) is NaN.
28 * x = a floating point number.
30 * `true` if $(D_PARAM x) is Nan.
32 bool isNaN(X
)(X x
) @nogc @trusted pure nothrow
33 if (isFloatingPoint
!(X
))
42 Code kept for historical context. At least on Intel, the simple test
43 x != x uses one dedicated instruction (ucomiss/ucomisd) that runs in one
44 cycle. Code for 80- and 128-bits is larger but still smaller than the
45 integrals-based solutions below. Future revisions may enable the code
46 below conditionally depending on hardware.
48 alias F
= floatTraits
!(X
);
49 static if (F
.realFormat
== RealFormat
.ieeeSingle
)
51 const uint p
= *cast(uint *)&x
;
52 // Sign bit (MSB) is irrelevant so mask it out.
53 // Next 8 bits should be all set.
54 // At least one bit among the least significant 23 bits should be set.
55 return (p
& 0x7FFF_FFFF
) > 0x7F80_0000;
57 else static if (F
.realFormat
== RealFormat
.ieeeDouble
)
59 const ulong p
= *cast(ulong *)&x
;
60 // Sign bit (MSB) is irrelevant so mask it out.
61 // Next 11 bits should be all set.
62 // At least one bit among the least significant 52 bits should be set.
63 return (p
& 0x7FFF_FFFF_FFFF_FFFF
) > 0x7FF0_0000_0000_0000;
65 else static if (F
.realFormat
== RealFormat
.ieeeExtended ||
66 F
.realFormat
== RealFormat
.ieeeExtended53
)
68 const ushort e
= F
.EXPMASK
& (cast(ushort *)&x
)[F
.EXPPOS_SHORT
];
69 const ulong ps
= *cast(ulong *)&x
;
70 return e
== F
.EXPMASK
&&
71 ps
& 0x7FFF_FFFF_FFFF_FFFF
; // not infinity
73 else static if (F
.realFormat
== RealFormat
.ieeeQuadruple
)
75 const ushort e
= F
.EXPMASK
& (cast(ushort *)&x
)[F
.EXPPOS_SHORT
];
76 const ulong psLsb
= (cast(ulong *)&x
)[MANTISSA_LSB
];
77 const ulong psMsb
= (cast(ulong *)&x
)[MANTISSA_MSB
];
78 return e
== F
.EXPMASK
&&
79 (psLsb |
(psMsb
& 0x0000_FFFF_FFFF_FFFF
)) != 0;
89 @safe pure nothrow @nogc unittest
91 assert( isNaN(float.init
));
92 assert( isNaN(-double.init
));
93 assert( isNaN(real.nan
));
94 assert( isNaN(-real.nan
));
95 assert(!isNaN(cast(float) 53.6));
96 assert(!isNaN(cast(real)-53.6));
99 @safe pure nothrow @nogc unittest
101 import std
.meta
: AliasSeq
;
103 static foreach (T
; AliasSeq
!(float, double, real))
106 assert(isNaN(T
.init
));
107 assert(isNaN(-T
.init
));
108 assert(isNaN(T
.nan
));
109 assert(isNaN(-T
.nan
));
110 assert(!isNaN(T
.infinity
));
111 assert(!isNaN(-T
.infinity
));
112 assert(!isNaN(cast(T
) 53.6));
113 assert(!isNaN(cast(T
)-53.6));
132 /*********************************
133 * Determines if $(D_PARAM x) is finite.
135 * x = a floating point number.
137 * `true` if $(D_PARAM x) is finite.
139 bool isFinite(X
)(X x
) @trusted pure nothrow @nogc
141 import std
.math
.traits
: floatTraits
, RealFormat
;
143 static if (__traits(isFloating
, X
))
145 return x
== x
&& x
!= X
.infinity
&& x
!= -X
.infinity
;
146 alias F
= floatTraits
!(X
);
147 ushort* pe
= cast(ushort *)&x
;
148 return (pe
[F
.EXPPOS_SHORT
] & F
.EXPMASK
) != F
.EXPMASK
;
152 @safe pure nothrow @nogc unittest
154 assert( isFinite(1.23f));
155 assert( isFinite(float.max
));
156 assert( isFinite(float.min_normal
));
157 assert(!isFinite(float.nan
));
158 assert(!isFinite(float.infinity
));
161 @safe pure nothrow @nogc unittest
163 assert(isFinite(1.23));
164 assert(isFinite(double.max
));
165 assert(isFinite(double.min_normal
));
166 assert(!isFinite(double.nan
));
167 assert(!isFinite(double.infinity
));
169 assert(isFinite(1.23L));
170 assert(isFinite(real.max
));
171 assert(isFinite(real.min_normal
));
172 assert(!isFinite(real.nan
));
173 assert(!isFinite(real.infinity
));
176 static assert(isFinite(1.23));
177 static assert(isFinite(double.max
));
178 static assert(isFinite(double.min_normal
));
179 static assert(!isFinite(double.nan
));
180 static assert(!isFinite(double.infinity
));
182 static assert(isFinite(1.23L));
183 static assert(isFinite(real.max
));
184 static assert(isFinite(real.min_normal
));
185 static assert(!isFinite(real.nan
));
186 static assert(!isFinite(real.infinity
));
190 /*********************************
191 * Determines if $(D_PARAM x) is normalized.
193 * A normalized number must not be zero, subnormal, infinite nor $(NAN).
196 * x = a floating point number.
198 * `true` if $(D_PARAM x) is normalized.
201 /* Need one for each format because subnormal floats might
202 * be converted to normal reals.
204 bool isNormal(X
)(X x
) @trusted pure nothrow @nogc
206 import std
.math
.traits
: floatTraits
, RealFormat
;
208 static if (__traits(isFloating
, X
))
210 return (x
<= -X
.min_normal
&& x
!= -X
.infinity
) ||
(x
>= X
.min_normal
&& x
!= X
.infinity
);
211 alias F
= floatTraits
!(X
);
212 ushort e
= F
.EXPMASK
& (cast(ushort *)&x
)[F
.EXPPOS_SHORT
];
213 return (e
!= F
.EXPMASK
&& e
!= 0);
217 @safe pure nothrow @nogc unittest
227 assert(!isNormal(f
));
228 assert(!isNormal(d
));
229 assert(!isNormal(e
));
230 assert(!isNormal(real.infinity
));
231 assert(isNormal(-real.max
));
232 assert(!isNormal(real.min_normal
/4));
236 @safe pure nothrow @nogc unittest
241 enum real e
= 10e+48;
243 static assert(isNormal(f
));
244 static assert(isNormal(d
));
245 static assert(isNormal(e
));
247 static assert(!isNormal(0.0f));
248 static assert(!isNormal(0.0));
249 static assert(!isNormal(0.0L));
250 static assert(!isNormal(real.infinity
));
251 static assert(isNormal(-real.max
));
252 static assert(!isNormal(real.min_normal
/4));
255 /*********************************
256 * Determines if $(D_PARAM x) is subnormal.
258 * Subnormals (also known as "denormal number"), have a 0 exponent
259 * and a 0 most significant mantissa bit.
262 * x = a floating point number.
264 * `true` if $(D_PARAM x) is a denormal number.
266 bool isSubnormal(X
)(X x
) @trusted pure nothrow @nogc
268 import std
.math
.traits
: floatTraits
, RealFormat
, MANTISSA_MSB
, MANTISSA_LSB
;
270 static if (__traits(isFloating
, X
))
272 return -X
.min_normal
< x
&& x
< X
.min_normal
;
274 Need one for each format because subnormal floats might
275 be converted to normal reals.
277 alias F
= floatTraits
!(X
);
278 static if (F
.realFormat
== RealFormat
.ieeeSingle
)
280 uint *p
= cast(uint *)&x
;
281 return (*p
& F
.EXPMASK_INT
) == 0 && *p
& F
.MANTISSAMASK_INT
;
283 else static if (F
.realFormat
== RealFormat
.ieeeDouble
)
285 uint *p
= cast(uint *)&x
;
286 return (p
[MANTISSA_MSB
] & F
.EXPMASK_INT
) == 0
287 && (p
[MANTISSA_LSB
] || p
[MANTISSA_MSB
] & F
.MANTISSAMASK_INT
);
289 else static if (F
.realFormat
== RealFormat
.ieeeQuadruple
)
291 ushort e
= F
.EXPMASK
& (cast(ushort *)&x
)[F
.EXPPOS_SHORT
];
292 long* ps
= cast(long *)&x
;
294 ((ps
[MANTISSA_LSB
]|
(ps
[MANTISSA_MSB
]& 0x0000_FFFF_FFFF_FFFF
)) != 0));
296 else static if (F
.realFormat
== RealFormat
.ieeeExtended ||
297 F
.realFormat
== RealFormat
.ieeeExtended53
)
299 ushort* pe
= cast(ushort *)&x
;
300 long* ps
= cast(long *)&x
;
302 return (pe
[F
.EXPPOS_SHORT
] & F
.EXPMASK
) == 0 && *ps
> 0;
306 static assert(false, "Not implemented for this architecture");
311 @safe pure nothrow @nogc unittest
313 import std
.meta
: AliasSeq
;
315 static foreach (T
; AliasSeq
!(float, double, real))
318 for (f
= 1.0; !isSubnormal(f
); f
/= 2)
323 @safe pure nothrow @nogc unittest
325 static bool subnormalTest(T
)()
328 for (f
= 1.0; !isSubnormal(f
); f
/= 2)
333 static assert(subnormalTest
!float());
334 static assert(subnormalTest
!double());
335 static assert(subnormalTest
!real());
338 /*********************************
339 * Determines if $(D_PARAM x) is $(PLUSMN)$(INFIN).
341 * x = a floating point number.
343 * `true` if $(D_PARAM x) is $(PLUSMN)$(INFIN).
345 bool isInfinity(X
)(X x
) @nogc @trusted pure nothrow
346 if (isFloatingPoint
!(X
))
348 import std
.math
.traits
: floatTraits
, RealFormat
, MANTISSA_MSB
, MANTISSA_LSB
;
350 alias F
= floatTraits
!(X
);
351 static if (F
.realFormat
== RealFormat
.ieeeSingle
)
353 return ((*cast(uint *)&x
) & 0x7FFF_FFFF
) == 0x7F80_0000;
355 else static if (F
.realFormat
== RealFormat
.ieeeDouble
)
357 return ((*cast(ulong *)&x
) & 0x7FFF_FFFF_FFFF_FFFF
)
358 == 0x7FF0_0000_0000_0000;
360 else static if (F
.realFormat
== RealFormat
.ieeeExtended ||
361 F
.realFormat
== RealFormat
.ieeeExtended53
)
363 const ushort e
= cast(ushort)(F
.EXPMASK
& (cast(ushort *)&x
)[F
.EXPPOS_SHORT
]);
364 const ulong ps
= *cast(ulong *)&x
;
366 // On Motorola 68K, infinity can have hidden bit = 1 or 0. On x86, it is always 1.
367 return e
== F
.EXPMASK
&& (ps
& 0x7FFF_FFFF_FFFF_FFFF
) == 0;
369 else static if (F
.realFormat
== RealFormat
.ieeeQuadruple
)
371 const long psLsb
= (cast(long *)&x
)[MANTISSA_LSB
];
372 const long psMsb
= (cast(long *)&x
)[MANTISSA_MSB
];
374 && (psMsb
& 0x7FFF_FFFF_FFFF_FFFF
) == 0x7FFF_0000_0000_0000;
378 return (x
< -X
.max
) ||
(X
.max
< x
);
383 @nogc @safe pure nothrow unittest
385 assert(!isInfinity(float.init
));
386 assert(!isInfinity(-float.init
));
387 assert(!isInfinity(float.nan
));
388 assert(!isInfinity(-float.nan
));
389 assert(isInfinity(float.infinity
));
390 assert(isInfinity(-float.infinity
));
391 assert(isInfinity(-1.0f / 0.0f));
394 @safe pure nothrow @nogc unittest
397 assert(!isInfinity(double.init
));
398 assert(!isInfinity(-double.init
));
399 assert(!isInfinity(double.nan
));
400 assert(!isInfinity(-double.nan
));
401 assert(isInfinity(double.infinity
));
402 assert(isInfinity(-double.infinity
));
403 assert(isInfinity(-1.0 / 0.0));
405 assert(!isInfinity(real.init
));
406 assert(!isInfinity(-real.init
));
407 assert(!isInfinity(real.nan
));
408 assert(!isInfinity(-real.nan
));
409 assert(isInfinity(real.infinity
));
410 assert(isInfinity(-real.infinity
));
411 assert(isInfinity(-1.0L / 0.0L));
416 assert(!isInfinity(f
));
417 assert(!isInfinity(-f
));
419 assert(!isInfinity(f
));
420 assert(!isInfinity(-f
));
422 assert(isInfinity(f
));
423 assert(isInfinity(-f
));
425 assert(isInfinity(f
));
429 assert(!isInfinity(d
));
430 assert(!isInfinity(-d
));
432 assert(!isInfinity(d
));
433 assert(!isInfinity(-d
));
435 assert(isInfinity(d
));
436 assert(isInfinity(-d
));
438 assert(isInfinity(d
));
442 assert(!isInfinity(e
));
443 assert(!isInfinity(-e
));
445 assert(!isInfinity(e
));
446 assert(!isInfinity(-e
));
448 assert(isInfinity(e
));
449 assert(isInfinity(-e
));
451 assert(isInfinity(e
));
454 @nogc @safe pure nothrow unittest
456 import std
.meta
: AliasSeq
;
457 static bool foo(T
)(inout T x
) { return isInfinity(x
); }
458 foreach (T
; AliasSeq
!(float, double, real))
460 assert(!foo(T(3.14f)));
461 assert(foo(T
.infinity
));
465 /*********************************
466 * Is the binary representation of x identical to y?
468 bool isIdentical(real x
, real y
) @trusted pure nothrow @nogc
472 if (x
!is y
) return false;
473 if (x
== x
) return true; // If not NaN `is` implies identical representation.
474 static if (double.mant_dig
!= real.mant_dig
)
476 // Works because we are in CTFE and there is no way in CTFE to set more
477 // bits of NaN payload than can fit in a double, and since 2.087
478 // changed real.init to be non-signaling I *think* there is no way in
479 // CTFE for a real to be a signaling NaN unless real and double have
480 // the same representation so real's bits can be manipulated directly.
481 double d1
= x
, d2
= y
;
485 // Alias to avoid converting signaling to quiet.
489 return *cast(long*) &d1
== *cast(long*) &d2
;
491 // We're doing a bitwise comparison so the endianness is irrelevant.
492 long* pxs
= cast(long *)&x
;
493 long* pys
= cast(long *)&y
;
494 alias F
= floatTraits
!(real);
495 static if (F
.realFormat
== RealFormat
.ieeeDouble
)
497 return pxs
[0] == pys
[0];
499 else static if (F
.realFormat
== RealFormat
.ieeeQuadruple
)
501 return pxs
[0] == pys
[0] && pxs
[1] == pys
[1];
503 else static if (F
.realFormat
== RealFormat
.ieeeExtended
)
505 ushort* pxe
= cast(ushort *)&x
;
506 ushort* pye
= cast(ushort *)&y
;
507 return pxe
[4] == pye
[4] && pxs
[0] == pys
[0];
511 assert(0, "isIdentical not implemented");
515 @safe @nogc pure nothrow unittest
517 // We're forcing the CTFE to run by assigning the result of the function to an enum
518 enum test1
= isIdentical(1.0,1.0);
519 enum test2
= isIdentical(real.nan
,real.nan
);
520 enum test3
= isIdentical(real.infinity
, real.infinity
);
521 enum test4
= isIdentical(real.infinity
, real.infinity
);
522 enum test5
= isIdentical(0.0, 0.0);
530 enum test6
= !isIdentical(0.0, -0.0);
531 enum test7
= !isIdentical(real.nan
, -real.nan
);
532 enum test8
= !isIdentical(real.infinity
, -real.infinity
);
539 @safe @nogc pure nothrow unittest
541 assert( !isIdentical(1.2,1.3));
542 assert( isIdentical(0.0, 0.0));
543 assert( isIdentical(1.0, 1.0));
544 assert( isIdentical(real.infinity
, real.infinity
));
545 assert( isIdentical(-real.infinity
, -real.infinity
));
546 assert( isIdentical(real.nan
, real.nan
));
548 assert(!isIdentical(0.0, -0.0));
549 assert(!isIdentical(real.nan
, -real.nan
));
550 assert(!isIdentical(real.infinity
, -real.infinity
));
552 /*********************************
553 * Return 1 if sign bit of e is set, 0 if not.
555 int signbit(X
)(X x
) @nogc @trusted pure nothrow
557 import std
.math
.traits
: floatTraits
, RealFormat
;
561 double dval
= cast(double) x
; // Precision can increase or decrease but sign won't change (even NaN).
562 return 0 > *cast(long*) &dval
;
565 alias F
= floatTraits
!(X
);
566 return ((cast(ubyte *)&x
)[F
.SIGNPOS_BYTE
] & 0x80) != 0;
570 @nogc @safe pure nothrow unittest
572 assert(!signbit(float.nan
));
573 assert(signbit(-float.nan
));
574 assert(!signbit(168.1234f));
575 assert(signbit(-168.1234f));
576 assert(!signbit(0.0f));
577 assert(signbit(-0.0f));
578 assert(signbit(-float.max
));
579 assert(!signbit(float.max
));
581 assert(!signbit(double.nan
));
582 assert(signbit(-double.nan
));
583 assert(!signbit(168.1234));
584 assert(signbit(-168.1234));
585 assert(!signbit(0.0));
586 assert(signbit(-0.0));
587 assert(signbit(-double.max
));
588 assert(!signbit(double.max
));
590 assert(!signbit(real.nan
));
591 assert(signbit(-real.nan
));
592 assert(!signbit(168.1234L));
593 assert(signbit(-168.1234L));
594 assert(!signbit(0.0L));
595 assert(signbit(-0.0L));
596 assert(signbit(-real.max
));
597 assert(!signbit(real.max
));
600 @nogc @safe pure nothrow unittest
603 static assert(!signbit(float.nan
));
604 static assert(signbit(-float.nan
));
605 static assert(!signbit(168.1234f));
606 static assert(signbit(-168.1234f));
607 static assert(!signbit(0.0f));
608 static assert(signbit(-0.0f));
609 static assert(signbit(-float.max
));
610 static assert(!signbit(float.max
));
612 static assert(!signbit(double.nan
));
613 static assert(signbit(-double.nan
));
614 static assert(!signbit(168.1234));
615 static assert(signbit(-168.1234));
616 static assert(!signbit(0.0));
617 static assert(signbit(-0.0));
618 static assert(signbit(-double.max
));
619 static assert(!signbit(double.max
));
621 static assert(!signbit(real.nan
));
622 static assert(signbit(-real.nan
));
623 static assert(!signbit(168.1234L));
624 static assert(signbit(-168.1234L));
625 static assert(!signbit(0.0L));
626 static assert(signbit(-0.0L));
627 static assert(signbit(-real.max
));
628 static assert(!signbit(real.max
));
633 to = the numeric value to use
634 from = the sign value to use
636 a value composed of to with from's sign bit.
638 R
copysign(R
, X
)(R to
, X from
) @trusted pure nothrow @nogc
639 if (isFloatingPoint
!(R
) && isFloatingPoint
!(X
))
641 import std
.math
.traits
: floatTraits
, RealFormat
;
645 return signbit(to
) == signbit(from
) ? to
: -to
;
647 ubyte* pto
= cast(ubyte *)&to
;
648 const ubyte* pfrom
= cast(ubyte *)&from
;
650 alias T
= floatTraits
!(R
);
651 alias F
= floatTraits
!(X
);
652 pto
[T
.SIGNPOS_BYTE
] &= 0x7F;
653 pto
[T
.SIGNPOS_BYTE
] |
= pfrom
[F
.SIGNPOS_BYTE
] & 0x80;
658 R
copysign(R
, X
)(X to
, R from
) @trusted pure nothrow @nogc
659 if (isIntegral
!(X
) && isFloatingPoint
!(R
))
661 return copysign(cast(R
) to
, from
);
665 @safe pure nothrow @nogc unittest
667 assert(copysign(1.0, 1.0) == 1.0);
668 assert(copysign(1.0, -0.0) == -1.0);
669 assert(copysign(1UL, -1.0) == -1.0);
670 assert(copysign(-1.0, -1.0) == -1.0);
672 assert(copysign(real.infinity
, -1.0) == -real.infinity
);
673 assert(copysign(real.nan
, 1.0) is real.nan
);
674 assert(copysign(-real.nan
, 1.0) is real.nan
);
675 assert(copysign(real.nan
, -1.0) is -real.nan
);
678 @safe pure nothrow @nogc unittest
680 import std
.meta
: AliasSeq
;
682 static foreach (X
; AliasSeq
!(float, double, real, int, long))
684 static foreach (Y
; AliasSeq
!(float, double, real))
699 e
= copysign(-x
, -y
);
702 static if (isFloatingPoint
!X
)
704 e
= copysign(X
.nan
, y
);
705 assert(isNaN(e
) && !signbit(e
));
707 e
= copysign(X
.nan
, -y
);
708 assert(isNaN(e
) && signbit(e
));
713 static foreach (X
; AliasSeq
!(float, double, real, int, long))
715 static foreach (Y
; AliasSeq
!(float, double, real))
720 assert(21.0 == copysign(x
, y
));
721 assert(21.0 == copysign(-x
, y
));
722 assert(-21.0 == copysign(x
, -y
));
723 assert(-21.0 == copysign(-x
, -y
));
725 static if (isFloatingPoint
!X
)
727 static assert(isNaN(copysign(X
.nan
, y
)) && !signbit(copysign(X
.nan
, y
)));
728 assert(isNaN(copysign(X
.nan
, -y
)) && signbit(copysign(X
.nan
, -y
)));
734 /*********************************
735 Returns `-1` if $(D x < 0), `x` if $(D x == 0), `1` if
736 $(D x > 0), and $(NAN) if x==$(NAN).
738 F
sgn(F
)(F x
) @safe pure nothrow @nogc
739 if (isFloatingPoint
!F || isIntegral
!F
)
741 // @@@TODO@@@: make this faster
742 return x
> 0 ?
1 : x
< 0 ?
-1 : x
;
746 @safe pure nothrow @nogc unittest
748 assert(sgn(168.1234) == 1);
749 assert(sgn(-168.1234) == -1);
750 assert(sgn(0.0) == 0);
751 assert(sgn(-0.0) == 0);
755 Check whether a number is an integer power of two.
757 Note that only positive numbers can be integer powers of two. This
758 function always return `false` if `x` is negative or zero.
761 x = the number to test
764 `true` if `x` is an integer power of two.
766 bool isPowerOf2(X
)(const X x
) pure @safe nothrow @nogc
769 import std
.math
.exponential
: frexp
;
771 static if (isFloatingPoint
!X
)
774 const X sig
= frexp(x
, exp
);
776 return (exp
!= int.min
) && (sig
is cast(X
) 0.5L);
780 static if (isSigned
!X
)
782 auto y
= cast(typeof(x
+ 0))x
;
783 return y
> 0 && !(y
& (y
- 1));
787 auto y
= cast(typeof(x
+ 0u))x
;
788 return (y
& -y
) > (y
- 1);
795 import std
.math
.exponential
: pow
;
797 assert( isPowerOf2(1.0L));
798 assert( isPowerOf2(2.0L));
799 assert( isPowerOf2(0.5L));
800 assert( isPowerOf2(pow(2.0L, 96)));
801 assert( isPowerOf2(pow(2.0L, -77)));
803 assert(!isPowerOf2(-2.0L));
804 assert(!isPowerOf2(-0.5L));
805 assert(!isPowerOf2(0.0L));
806 assert(!isPowerOf2(4.315));
807 assert(!isPowerOf2(1.0L / 3.0L));
809 assert(!isPowerOf2(real.nan
));
810 assert(!isPowerOf2(real.infinity
));
815 assert( isPowerOf2(1));
816 assert( isPowerOf2(2));
817 assert( isPowerOf2(1uL << 63));
819 assert(!isPowerOf2(-4));
820 assert(!isPowerOf2(0));
821 assert(!isPowerOf2(1337u));
826 import std
.math
.exponential
: pow
;
827 import std
.meta
: AliasSeq
;
829 enum smallP2
= pow(2.0L, -62);
830 enum bigP2
= pow(2.0L, 50);
831 enum smallP7
= pow(7.0L, -35);
832 enum bigP7
= pow(7.0L, 30);
834 static foreach (X
; AliasSeq
!(float, double, real))
836 immutable min_sub
= X
.min_normal
* X
.epsilon
;
838 foreach (x
; [smallP2
, min_sub
, X
.min_normal
, .25L, 0.5L, 1.0L,
839 2.0L, 8.0L, pow(2.0L, X
.max_exp
- 1), bigP2
])
841 assert( isPowerOf2(cast(X
) x
));
842 assert(!isPowerOf2(cast(X
)-x
));
845 foreach (x
; [0.0L, 3 * min_sub
, smallP7
, 0.1L, 1337.0L, bigP7
, X
.max
, real.nan
, real.infinity
])
847 assert(!isPowerOf2(cast(X
) x
));
848 assert(!isPowerOf2(cast(X
)-x
));
852 static foreach (X
; AliasSeq
!(byte, ubyte, short, ushort, int, uint, long, ulong))
854 foreach (x
; [1, 2, 4, 8, (X
.max
>>> 1) + 1])
856 assert( isPowerOf2(cast(X
) x
));
857 static if (isSigned
!X
)
858 assert(!isPowerOf2(cast(X
)-x
));
861 foreach (x
; [0, 3, 5, 13, 77, X
.min
, X
.max
])
862 assert(!isPowerOf2(cast(X
) x
));
866 static foreach (X
; AliasSeq
!(float, double, real))
868 enum min_sub
= X
.min_normal
* X
.epsilon
;
870 static foreach (x
; [smallP2
, min_sub
, X
.min_normal
, .25L, 0.5L, 1.0L,
871 2.0L, 8.0L, pow(2.0L, X
.max_exp
- 1), bigP2
])
873 static assert( isPowerOf2(cast(X
) x
));
874 static assert(!isPowerOf2(cast(X
)-x
));
877 static foreach (x
; [0.0L, 3 * min_sub
, smallP7
, 0.1L, 1337.0L, bigP7
, X
.max
, real.nan
, real.infinity
])
879 static assert(!isPowerOf2(cast(X
) x
));
880 static assert(!isPowerOf2(cast(X
)-x
));
884 static foreach (X
; AliasSeq
!(byte, ubyte, short, ushort, int, uint, long, ulong))
886 static foreach (x
; [1, 2, 4, 8, (X
.max
>>> 1) + 1])
888 static assert( isPowerOf2(cast(X
) x
));
889 static if (isSigned
!X
)
890 static assert(!isPowerOf2(cast(X
)-x
));
893 static foreach (x
; [0, 3, 5, 13, 77, X
.min
, X
.max
])
894 static assert(!isPowerOf2(cast(X
) x
));
898 // Underlying format exposed through floatTraits
904 ieeeExtended
, // x87 80-bit real
905 ieeeExtended53
, // x87 real rounded to precision of double.
906 ibmExtended
, // IBM 128-bit extended
910 // Constants used for extracting the components of the representation.
911 // They supplement the built-in floating point properties.
912 template floatTraits(T
)
914 import std
.traits
: Unqual
;
916 // EXPMASK is a ushort mask to select the exponent portion (without sign)
917 // EXPSHIFT is the number of bits the exponent is left-shifted by in its ushort
918 // EXPBIAS is the exponent bias - 1 (exp == EXPBIAS yields ×2^-1).
919 // EXPPOS_SHORT is the index of the exponent when represented as a ushort array.
920 // SIGNPOS_BYTE is the index of the sign when represented as a ubyte array.
921 // RECIP_EPSILON is the value such that (smallest_subnormal) * RECIP_EPSILON == T.min_normal
922 enum Unqual
!T RECIP_EPSILON
= (1/T
.epsilon
);
923 static if (T
.mant_dig
== 24)
925 // Single precision float
926 enum ushort EXPMASK
= 0x7F80;
927 enum ushort EXPSHIFT
= 7;
928 enum ushort EXPBIAS
= 0x3F00;
929 enum uint EXPMASK_INT
= 0x7F80_0000;
930 enum uint MANTISSAMASK_INT
= 0x007F_FFFF
;
931 enum realFormat
= RealFormat
.ieeeSingle
;
932 version (LittleEndian
)
934 enum EXPPOS_SHORT
= 1;
935 enum SIGNPOS_BYTE
= 3;
939 enum EXPPOS_SHORT
= 0;
940 enum SIGNPOS_BYTE
= 0;
943 else static if (T
.mant_dig
== 53)
945 static if (T
.sizeof
== 8)
947 // Double precision float, or real == double
948 enum ushort EXPMASK
= 0x7FF0;
949 enum ushort EXPSHIFT
= 4;
950 enum ushort EXPBIAS
= 0x3FE0;
951 enum uint EXPMASK_INT
= 0x7FF0_0000;
952 enum uint MANTISSAMASK_INT
= 0x000F_FFFF
; // for the MSB only
953 enum ulong MANTISSAMASK_LONG
= 0x000F_FFFF_FFFF_FFFF
;
954 enum realFormat
= RealFormat
.ieeeDouble
;
955 version (LittleEndian
)
957 enum EXPPOS_SHORT
= 3;
958 enum SIGNPOS_BYTE
= 7;
962 enum EXPPOS_SHORT
= 0;
963 enum SIGNPOS_BYTE
= 0;
966 else static if (T
.sizeof
== 12)
968 // Intel extended real80 rounded to double
969 enum ushort EXPMASK
= 0x7FFF;
970 enum ushort EXPSHIFT
= 0;
971 enum ushort EXPBIAS
= 0x3FFE;
972 enum realFormat
= RealFormat
.ieeeExtended53
;
973 version (LittleEndian
)
975 enum EXPPOS_SHORT
= 4;
976 enum SIGNPOS_BYTE
= 9;
980 enum EXPPOS_SHORT
= 0;
981 enum SIGNPOS_BYTE
= 0;
985 static assert(false, "No traits support for " ~ T
.stringof
);
987 else static if (T
.mant_dig
== 64)
989 // Intel extended real80
990 enum ushort EXPMASK
= 0x7FFF;
991 enum ushort EXPSHIFT
= 0;
992 enum ushort EXPBIAS
= 0x3FFE;
993 enum realFormat
= RealFormat
.ieeeExtended
;
994 version (LittleEndian
)
996 enum EXPPOS_SHORT
= 4;
997 enum SIGNPOS_BYTE
= 9;
1001 enum EXPPOS_SHORT
= 0;
1002 enum SIGNPOS_BYTE
= 0;
1005 else static if (T
.mant_dig
== 113)
1007 // Quadruple precision float
1008 enum ushort EXPMASK
= 0x7FFF;
1009 enum ushort EXPSHIFT
= 0;
1010 enum ushort EXPBIAS
= 0x3FFE;
1011 enum realFormat
= RealFormat
.ieeeQuadruple
;
1012 version (LittleEndian
)
1014 enum EXPPOS_SHORT
= 7;
1015 enum SIGNPOS_BYTE
= 15;
1019 enum EXPPOS_SHORT
= 0;
1020 enum SIGNPOS_BYTE
= 0;
1023 else static if (T
.mant_dig
== 106)
1025 // IBM Extended doubledouble
1026 enum ushort EXPMASK
= 0x7FF0;
1027 enum ushort EXPSHIFT
= 4;
1028 enum realFormat
= RealFormat
.ibmExtended
;
1030 // For IBM doubledouble the larger magnitude double comes first.
1031 // It's really a double[2] and arrays don't index differently
1032 // between little and big-endian targets.
1033 enum DOUBLEPAIR_MSB
= 0;
1034 enum DOUBLEPAIR_LSB
= 1;
1036 // The exponent/sign byte is for most significant part.
1037 version (LittleEndian
)
1039 enum EXPPOS_SHORT
= 3;
1040 enum SIGNPOS_BYTE
= 7;
1044 enum EXPPOS_SHORT
= 0;
1045 enum SIGNPOS_BYTE
= 0;
1049 static assert(false, "No traits support for " ~ T
.stringof
);
1052 // These apply to all floating-point types
1053 version (LittleEndian
)
1055 enum MANTISSA_LSB
= 0;
1056 enum MANTISSA_MSB
= 1;
1060 enum MANTISSA_LSB
= 1;
1061 enum MANTISSA_MSB
= 0;