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