1 // Written in the D programming language.
4 This is a submodule of $(MREF std, math).
6 It contains classical algebraic functions like `abs`, `sqrt`, and `poly`.
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/algebraic.d)
15 TABLE_SV = <table border="1" cellpadding="4" cellspacing="0">
16 <caption>Special Values</caption>
19 POWER = $1<sup>$2</sup>
23 PLUSMNINF = ±∞
28 module std
.math
.algebraic
;
30 static import core
.math
;
31 static import core
.stdc
.math
;
32 import std
.traits
: CommonType
, isFloatingPoint
, isIntegral
, isSigned
, Unqual
;
34 /***********************************
35 * Calculates the absolute value of a number.
38 * Num = (template parameter) type of number
39 * x = real number value
42 * The absolute value of the number. If floating-point or integral,
43 * the return type will be the same as the input.
46 * When x is a signed integral equal to `Num.min` the value of x will be returned instead.
47 * Note for 2's complement; `-Num.min` (= `Num.max + 1`) is not representable due to overflow.
49 auto abs(Num
)(Num x
) @nogc nothrow pure
50 if (isIntegral
!Num ||
(is(typeof(Num
.init
>= 0)) && is(typeof(-Num
.init
))))
52 static if (isFloatingPoint
!(Num
))
56 static if (isIntegral
!Num
)
57 return x
>= 0 ? x
: cast(Num
) -x
;
59 return x
>= 0 ? x
: -x
;
64 @safe pure nothrow @nogc unittest
66 import std
.math
.traits
: isIdentical
, isNaN
;
68 assert(isIdentical(abs(-0.0L), 0.0L));
69 assert(isNaN(abs(real.nan
)));
70 assert(abs(-real.infinity
) == real.infinity
);
71 assert(abs(-56) == 56);
72 assert(abs(2321312L) == 2321312L);
73 assert(abs(23u) == 23u);
76 @safe pure nothrow @nogc unittest
78 assert(abs(byte(-8)) == 8);
79 assert(abs(ubyte(8u)) == 8);
80 assert(abs(short(-8)) == 8);
81 assert(abs(ushort(8u)) == 8);
82 assert(abs(int(-8)) == 8);
83 assert(abs(uint(8u)) == 8);
84 assert(abs(long(-8)) == 8);
85 assert(abs(ulong(8u)) == 8);
86 assert(is(typeof(abs(byte(-8))) == byte));
87 assert(is(typeof(abs(ubyte(8u))) == ubyte));
88 assert(is(typeof(abs(short(-8))) == short));
89 assert(is(typeof(abs(ushort(8u))) == ushort));
90 assert(is(typeof(abs(int(-8))) == int));
91 assert(is(typeof(abs(uint(8u))) == uint));
92 assert(is(typeof(abs(long(-8))) == long));
93 assert(is(typeof(abs(ulong(8u))) == ulong));
96 @safe pure nothrow @nogc unittest
98 import std
.meta
: AliasSeq
;
99 static foreach (T
; AliasSeq
!(float, double, real))
103 assert(abs(-f
) == f
);
107 // see https://issues.dlang.org/show_bug.cgi?id=20205
108 // to avoid falling into the trap again
109 @safe pure nothrow @nogc unittest
111 assert(50 - abs(-100) == -50);
114 // https://issues.dlang.org/show_bug.cgi?id=19162
117 struct Vector(T
, int size
)
122 static auto abs(T
, int size
)(auto ref const Vector
!(T
, size
) v
)
130 /*******************************
134 * $(TR $(TH x) $(TH fabs(x)))
135 * $(TR $(TD $(PLUSMN)0.0) $(TD +0.0) )
136 * $(TR $(TD $(PLUSMN)$(INFIN)) $(TD +$(INFIN)) )
140 real fabs(real x
) @safe pure nothrow @nogc { return core
.math
.fabs(x
); }
144 double fabs(double x
) @safe pure nothrow @nogc { return core
.math
.fabs(x
); }
148 float fabs(float x
) @safe pure nothrow @nogc { return core
.math
.fabs(x
); }
153 import std
.math
.traits
: isIdentical
;
155 assert(isIdentical(fabs(0.0f), 0.0f));
156 assert(isIdentical(fabs(-0.0f), 0.0f));
157 assert(fabs(-10.0f) == 10.0f);
159 assert(isIdentical(fabs(0.0), 0.0));
160 assert(isIdentical(fabs(-0.0), 0.0));
161 assert(fabs(-10.0) == 10.0);
163 assert(isIdentical(fabs(0.0L), 0.0L));
164 assert(isIdentical(fabs(-0.0L), 0.0L));
165 assert(fabs(-10.0L) == 10.0L);
170 real function(real) pfabs
= &fabs;
171 assert(pfabs
!= null);
174 @safe pure nothrow @nogc unittest
176 float f
= fabs(-2.0f);
179 double d
= fabs(-2.0);
182 real r
= fabs(-2.0L);
186 /***************************************
187 * Compute square root of x.
190 * $(TR $(TH x) $(TH sqrt(x)) $(TH invalid?))
191 * $(TR $(TD -0.0) $(TD -0.0) $(TD no))
192 * $(TR $(TD $(LT)0.0) $(TD $(NAN)) $(TD yes))
193 * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) $(TD no))
197 float sqrt(float x
) @nogc @safe pure nothrow { return core
.math
.sqrt(x
); }
201 double sqrt(double x
) @nogc @safe pure nothrow { return core
.math
.sqrt(x
); }
205 real sqrt(real x
) @nogc @safe pure nothrow { return core
.math
.sqrt(x
); }
208 @safe pure nothrow @nogc unittest
210 import std
.math
.operations
: feqrel
;
211 import std
.math
.traits
: isNaN
;
213 assert(sqrt(2.0).feqrel(1.4142) > 16);
214 assert(sqrt(9.0).feqrel(3.0) > 16);
216 assert(isNaN(sqrt(-1.0f)));
217 assert(isNaN(sqrt(-1.0)));
218 assert(isNaN(sqrt(-1.0L)));
223 // https://issues.dlang.org/show_bug.cgi?id=5305
224 float function(float) psqrtf
= &sqrt
;
225 assert(psqrtf
!= null);
226 double function(double) psqrtd
= &sqrt
;
227 assert(psqrtd
!= null);
228 real function(real) psqrtr
= &sqrt
;
229 assert(psqrtr
!= null);
232 enum ZX80
= sqrt(7.0f);
233 enum ZX81
= sqrt(7.0);
234 enum ZX82
= sqrt(7.0L);
237 @safe pure nothrow @nogc unittest
239 float f
= sqrt(2.0f);
240 assert(fabs(f
* f
- 2.0f) < .00001);
242 double d
= sqrt(2.0);
243 assert(fabs(d
* d
- 2.0) < .00001);
246 assert(fabs(r
* r
- 2.0) < .00001);
250 * Calculates the cube root of x.
253 * $(TR $(TH $(I x)) $(TH cbrt(x)) $(TH invalid?))
254 * $(TR $(TD $(PLUSMN)0.0) $(TD $(PLUSMN)0.0) $(TD no) )
255 * $(TR $(TD $(NAN)) $(TD $(NAN)) $(TD yes) )
256 * $(TR $(TD $(PLUSMN)$(INFIN)) $(TD $(PLUSMN)$(INFIN)) $(TD no) )
259 real cbrt(real x
) @trusted nothrow @nogc
261 version (CRuntime_Microsoft
)
263 import std
.math
.traits
: copysign
;
264 import std
.math
.exponential
: exp2
;
266 version (INLINE_YL2X
)
267 return copysign(exp2(core
.math
.yl2x(fabs(x
), 1.0L/3.0L)), x
);
269 return core
.stdc
.math
.cbrtl(x
);
272 return core
.stdc
.math
.cbrtl(x
);
278 import std
.math
.operations
: feqrel
;
280 assert(cbrt(1.0).feqrel(1.0) > 16);
281 assert(cbrt(27.0).feqrel(3.0) > 16);
282 assert(cbrt(15.625).feqrel(2.5) > 16);
285 /***********************************************************************
286 * Calculates the length of the
287 * hypotenuse of a right-angled triangle with sides of length x and y.
288 * The hypotenuse is the value of the square root of
289 * the sums of the squares of x and y:
291 * sqrt($(POWER x, 2) + $(POWER y, 2))
293 * Note that hypot(x, y), hypot(y, x) and
294 * hypot(x, -y) are equivalent.
297 * $(TR $(TH x) $(TH y) $(TH hypot(x, y)) $(TH invalid?))
298 * $(TR $(TD x) $(TD $(PLUSMN)0.0) $(TD |x|) $(TD no))
299 * $(TR $(TD $(PLUSMNINF)) $(TD y) $(TD +$(INFIN)) $(TD no))
300 * $(TR $(TD $(PLUSMNINF)) $(TD $(NAN)) $(TD +$(INFIN)) $(TD no))
303 T
hypot(T
)(const T x
, const T y
) @safe pure nothrow @nogc
304 if (isFloatingPoint
!T
)
306 // Scale x and y to avoid underflow and overflow.
307 // If one is huge and the other tiny, return the larger.
308 // If both are huge, avoid overflow by scaling by 2^^-N.
309 // If both are tiny, avoid underflow by scaling by 2^^N.
310 import core
.math
: fabs, sqrt
;
311 import std
.math
.traits
: floatTraits
, RealFormat
;
313 alias F
= floatTraits
!T
;
317 if (!(u
>= v
)) // check for NaN as well.
321 if (u
== T
.infinity
) return u
; // hypot(inf, nan) == inf
322 if (v
== T
.infinity
) return v
; // hypot(nan, inf) == inf
325 static if (F
.realFormat
== RealFormat
.ieeeSingle
)
327 enum SQRTMIN
= 0x1p
-60f;
328 enum SQRTMAX
= 0x1p
+60f;
329 enum SCALE_UNDERFLOW
= 0x1p
+90f;
330 enum SCALE_OVERFLOW
= 0x1p
-90f;
332 else static if (F
.realFormat
== RealFormat
.ieeeDouble ||
333 F
.realFormat
== RealFormat
.ieeeExtended53 ||
334 F
.realFormat
== RealFormat
.ibmExtended
)
336 enum SQRTMIN
= 0x1p
-450L;
337 enum SQRTMAX
= 0x1p
+500L;
338 enum SCALE_UNDERFLOW
= 0x1p
+600L;
339 enum SCALE_OVERFLOW
= 0x1p
-600L;
341 else static if (F
.realFormat
== RealFormat
.ieeeExtended ||
342 F
.realFormat
== RealFormat
.ieeeQuadruple
)
344 enum SQRTMIN
= 0x1p
-8000L;
345 enum SQRTMAX
= 0x1p
+8000L;
346 enum SCALE_UNDERFLOW
= 0x1p
+10000L;
347 enum SCALE_OVERFLOW
= 0x1p
-10000L;
350 assert(0, "hypot not implemented");
352 // Now u >= v, or else one is NaN.
356 // hypot(huge, huge) -- avoid overflow
357 ratio
= SCALE_UNDERFLOW
;
361 else if (u
<= SQRTMIN
)
363 // hypot (tiny, tiny) -- avoid underflow
364 // This is only necessary to avoid setting the underflow
366 ratio
= SCALE_OVERFLOW
;
367 u
*= SCALE_UNDERFLOW
;
368 v
*= SCALE_UNDERFLOW
;
371 if (u
* T
.epsilon
> v
)
373 // hypot (huge, tiny) = huge
377 // both are in the normal range
378 return ratio
* sqrt(u
*u
+ v
*v
);
384 import std
.math
.operations
: feqrel
;
386 assert(hypot(1.0, 1.0).feqrel(1.4142) > 16);
387 assert(hypot(3.0, 4.0).feqrel(5.0) > 16);
388 assert(hypot(real.infinity
, 1.0L) == real.infinity
);
389 assert(hypot(real.infinity
, real.nan
) == real.infinity
);
394 import std
.math
.operations
: feqrel
;
396 assert(hypot(1.0f, 1.0f).feqrel(1.4142f) > 16);
397 assert(hypot(3.0f, 4.0f).feqrel(5.0f) > 16);
398 assert(hypot(float.infinity
, 1.0f) == float.infinity
);
399 assert(hypot(float.infinity
, float.nan
) == float.infinity
);
401 assert(hypot(1.0L, 1.0L).feqrel(1.4142L) > 16);
402 assert(hypot(3.0L, 4.0L).feqrel(5.0L) > 16);
403 assert(hypot(double.infinity
, 1.0) == double.infinity
);
404 assert(hypot(double.infinity
, double.nan
) == double.infinity
);
409 import std
.math
.operations
: feqrel
;
410 import std
.math
.traits
: isIdentical
;
411 import std
.meta
: AliasSeq
;
413 static foreach (T
; AliasSeq
!(float, double, real))
415 static T
[3][] vals
= // x,y,hypot
423 [9.0, 9*T
.epsilon
, 9.0],
424 [88/(64*sqrt(T
.min_normal
)), 105/(64*sqrt(T
.min_normal
)), 137/(64*sqrt(T
.min_normal
))],
425 [88/(128*sqrt(T
.min_normal
)), 105/(128*sqrt(T
.min_normal
)), 137/(128*sqrt(T
.min_normal
))],
426 [3*T
.min_normal
*T
.epsilon
, 4*T
.min_normal
*T
.epsilon
, 5*T
.min_normal
*T
.epsilon
],
427 [ T
.min_normal
, T
.min_normal
, sqrt(2.0L)*T
.min_normal
],
428 [ T
.max
/sqrt(2.0L), T
.max
/sqrt(2.0L), T
.max
],
429 [ T
.infinity
, T
.nan
, T
.infinity
],
430 [ T
.nan
, T
.infinity
, T
.infinity
],
431 [ T
.nan
, T
.nan
, T
.nan
],
432 [ T
.nan
, T
.max
, T
.nan
],
433 [ T
.max
, T
.nan
, T
.nan
],
435 for (int i
= 0; i
< vals
.length
; i
++)
441 assert(isIdentical(z
,h
) ||
feqrel(z
, h
) >= T
.mant_dig
- 1);
446 /***********************************************************************
447 * Calculates the distance of the point (x, y, z) from the origin (0, 0, 0)
448 * in three-dimensional space.
449 * The distance is the value of the square root of the sums of the squares
452 * sqrt($(POWER x, 2) + $(POWER y, 2) + $(POWER z, 2))
454 * Note that the distance between two points (x1, y1, z1) and (x2, y2, z2)
455 * in three-dimensional space can be calculated as hypot(x2-x1, y2-y1, z2-z1).
458 * x = floating point value
459 * y = floating point value
460 * z = floating point value
463 * The square root of the sum of the squares of the given arguments.
465 T
hypot(T
)(const T x
, const T y
, const T z
) @safe pure nothrow @nogc
466 if (isFloatingPoint
!T
)
468 import core
.math
: fabs, sqrt
;
469 import std
.math
.operations
: fmax
;
470 const absx
= fabs(x
);
471 const absy
= fabs(y
);
472 const absz
= fabs(z
);
474 // Scale all parameters to avoid overflow.
475 const ratio
= fmax(absx
, fmax(absy
, absz
));
479 return ratio
* sqrt((absx
/ ratio
) * (absx
/ ratio
)
480 + (absy
/ ratio
) * (absy
/ ratio
)
481 + (absz
/ ratio
) * (absz
/ ratio
));
487 import std
.math
.operations
: isClose
;
489 assert(isClose(hypot(1.0, 2.0, 2.0), 3.0));
490 assert(isClose(hypot(2.0, 3.0, 6.0), 7.0));
491 assert(isClose(hypot(1.0, 4.0, 8.0), 9.0));
496 import std
.meta
: AliasSeq
;
497 import std
.math
.traits
: isIdentical
;
498 import std
.math
.operations
: isClose
;
499 static foreach (T
; AliasSeq
!(float, double, real))
501 static T
[4][] vals
= [
502 [ 0.0L, 0.0L, 0.0L, 0.0L ],
503 [ 0.0L, 1.0L, 1.0L, sqrt(2.0L) ],
504 [ 1.0L, 1.0L, 1.0L, sqrt(3.0L) ],
505 [ 1.0L, 2.0L, 2.0L, 3.0L ],
506 [ 2.0L, 3.0L, 6.0L, 7.0L ],
507 [ 1.0L, 4.0L, 8.0L, 9.0L ],
508 [ 4.0L, 4.0L, 7.0L, 9.0L ],
509 [ 12.0L, 16.0L, 21.0L, 29.0L ],
510 [ 1e+8L, 1.0L, 1e-8L, 1e+8L+5e-9L ],
511 [ 1.0L, 1e+8L, 1e-8L, 1e+8L+5e-9L ],
512 [ 1e-8L, 1.0L, 1e+8L, 1e+8L+5e-9L ],
513 [ 1e-2L, 1e-4L, 1e-4L, 0.010000999950004999375L ],
514 [ 2147483647.0L, 2147483647.0L, 2147483647.0L, 3719550785.027307813987L ]
516 for (int i
= 0; i
< vals
.length
; i
++)
522 T a
= hypot(x
, y
, z
);
523 assert(isIdentical(r
, a
) ||
isClose(r
, a
));
528 /***********************************
529 * Evaluate polynomial A(x) = $(SUB a, 0) + $(SUB a, 1)x + $(SUB a, 2)$(POWER x,2) +
530 * $(SUB a,3)$(POWER x,3); ...
532 * Uses Horner's rule A(x) = $(SUB a, 0) + x($(SUB a, 1) + x($(SUB a, 2) +
533 * x($(SUB a, 3) + ...)))
535 * x = the value to evaluate.
536 * A = array of coefficients $(SUB a, 0), $(SUB a, 1), etc.
538 Unqual
!(CommonType
!(T1
, T2
)) poly(T1
, T2
)(T1 x
, in T2
[] A
) @trusted pure nothrow @nogc
539 if (isFloatingPoint
!T1
&& isFloatingPoint
!T2
)
542 assert(A
.length
> 0);
546 static if (is(immutable T2
== immutable real))
548 return polyImpl(x
, A
);
552 return polyImplBase(x
, A
);
557 Unqual
!(CommonType
!(T1
, T2
)) poly(T1
, T2
, int N
)(T1 x
, ref const T2
[N
] A
) @safe pure nothrow @nogc
558 if (isFloatingPoint
!T1
&& isFloatingPoint
!T2
&& N
> 0 && N
<= 10)
560 // statically unrolled version for up to 10 coefficients
561 typeof(return) r
= A
[N
- 1];
562 static foreach (i
; 1 .. N
)
571 @safe nothrow @nogc unittest
574 static real[] pp
= [56.1L, 32.7L, 6];
576 assert(poly(x
, pp
) == (56.1L + (32.7L + 6.0L * x
) * x
));
579 @safe nothrow @nogc unittest
582 static double[] pp
= [56.1, 32.7, 6];
588 assert(poly(x
, pp
) == y
);
593 static assert(poly(3.0, [1.0, 2.0, 3.0]) == 34);
596 private Unqual
!(CommonType
!(T1
, T2
)) polyImplBase(T1
, T2
)(T1 x
, in T2
[] A
) @trusted pure nothrow @nogc
597 if (isFloatingPoint
!T1
&& isFloatingPoint
!T2
)
599 ptrdiff_t i
= A
.length
- 1;
600 typeof(return) r
= A
[i
];
609 version (linux
) version = GenericPosixVersion
;
610 else version (FreeBSD
) version = GenericPosixVersion
;
611 else version (OpenBSD
) version = GenericPosixVersion
;
612 else version (Solaris
) version = GenericPosixVersion
;
613 else version (DragonFlyBSD
) version = GenericPosixVersion
;
615 private real polyImpl(real x
, in real[] A
) @trusted pure nothrow @nogc
617 version (D_InlineAsm_X86
)
621 return polyImplBase(x
, A
);
625 // BUG: This code assumes a frame pointer in EBP.
626 asm pure nothrow @nogc // assembler by W. Bright
628 // EDX = (A.length - 1) * real.sizeof
629 mov ECX
,A
[EBP
] ; // ECX = A.length
631 lea EDX
,[ECX
][ECX
*8] ;
634 fld real ptr
[EDX
] ; // ST0 = coeff[ECX]
636 fld x
[EBP
] ; // ST0 = x
637 fxch ST(1) ; // ST1 = x, ST0 = r
639 L2
: fmul ST
,ST(1) ; // r *= x
640 fld real ptr
-10[EDX
] ;
641 sub EDX
,10 ; // deg--
645 fxch ST(1) ; // ST1 = r, ST0 = x
646 fstp ST(0) ; // dump x
651 else version (GenericPosixVersion
)
653 asm pure nothrow @nogc // assembler by W. Bright
655 // EDX = (A.length - 1) * real.sizeof
656 mov ECX
,A
[EBP
] ; // ECX = A.length
659 lea EDX
,[EDX
][ECX
*4] ;
661 fld real ptr
[EDX
] ; // ST0 = coeff[ECX]
663 fld x
[EBP
] ; // ST0 = x
664 fxch ST(1) ; // ST1 = x, ST0 = r
666 L2
: fmul ST
,ST(1) ; // r *= x
667 fld real ptr
-12[EDX
] ;
668 sub EDX
,12 ; // deg--
672 fxch ST(1) ; // ST1 = r, ST0 = x
673 fstp ST(0) ; // dump x
680 asm pure nothrow @nogc // assembler by W. Bright
682 // EDX = (A.length - 1) * real.sizeof
683 mov ECX
,A
[EBP
] ; // ECX = A.length
688 fld real ptr
[EDX
] ; // ST0 = coeff[ECX]
690 fld x
[EBP
] ; // ST0 = x
691 fxch ST(1) ; // ST1 = x, ST0 = r
693 L2
: fmul ST
,ST(1) ; // r *= x
694 fld real ptr
-16[EDX
] ;
695 sub EDX
,16 ; // deg--
699 fxch ST(1) ; // ST1 = r, ST0 = x
700 fstp ST(0) ; // dump x
712 return polyImplBase(x
, A
);
717 * Gives the next power of two after `val`. `T` can be any built-in
720 * If the operation would lead to an over/underflow, this function will
727 * the next power of two after `val`
729 T
nextPow2(T
)(const T val
)
732 return powIntegralImpl
!(PowType
.ceil
)(val
);
736 T
nextPow2(T
)(const T val
)
737 if (isFloatingPoint
!T
)
739 return powFloatingPointImpl
!(PowType
.ceil
)(val
);
743 @safe @nogc pure nothrow unittest
745 assert(nextPow2(2) == 4);
746 assert(nextPow2(10) == 16);
747 assert(nextPow2(4000) == 4096);
749 assert(nextPow2(-2) == -4);
750 assert(nextPow2(-10) == -16);
752 assert(nextPow2(uint.max
) == 0);
753 assert(nextPow2(uint.min
) == 0);
754 assert(nextPow2(size_t
.max
) == 0);
755 assert(nextPow2(size_t
.min
) == 0);
757 assert(nextPow2(int.max
) == 0);
758 assert(nextPow2(int.min
) == 0);
759 assert(nextPow2(long.max
) == 0);
760 assert(nextPow2(long.min
) == 0);
764 @safe @nogc pure nothrow unittest
766 assert(nextPow2(2.1) == 4.0);
767 assert(nextPow2(-2.0) == -4.0);
768 assert(nextPow2(0.25) == 0.5);
769 assert(nextPow2(-4.0) == -8.0);
771 assert(nextPow2(double.max
) == 0.0);
772 assert(nextPow2(double.infinity
) == double.infinity
);
775 @safe @nogc pure nothrow unittest
777 assert(nextPow2(ubyte(2)) == 4);
778 assert(nextPow2(ubyte(10)) == 16);
780 assert(nextPow2(byte(2)) == 4);
781 assert(nextPow2(byte(10)) == 16);
783 assert(nextPow2(short(2)) == 4);
784 assert(nextPow2(short(10)) == 16);
785 assert(nextPow2(short(4000)) == 4096);
787 assert(nextPow2(ushort(2)) == 4);
788 assert(nextPow2(ushort(10)) == 16);
789 assert(nextPow2(ushort(4000)) == 4096);
792 @safe @nogc pure nothrow unittest
794 foreach (ulong i
; 1 .. 62)
796 assert(nextPow2(1UL << i
) == 2UL << i
);
797 assert(nextPow2((1UL << i
) - 1) == 1UL << i
);
798 assert(nextPow2((1UL << i
) + 1) == 2UL << i
);
799 assert(nextPow2((1UL << i
) + (1UL<<(i
-1))) == 2UL << i
);
803 @safe @nogc pure nothrow unittest
805 import std
.math
.traits
: isNaN
;
806 import std
.meta
: AliasSeq
;
808 static foreach (T
; AliasSeq
!(float, double, real))
810 enum T subNormal
= T
.min_normal
/ 2;
812 static if (subNormal
) assert(nextPow2(subNormal
) == T
.min_normal
);
814 assert(nextPow2(T(0.0)) == 0.0);
816 assert(nextPow2(T(2.0)) == 4.0);
817 assert(nextPow2(T(2.1)) == 4.0);
818 assert(nextPow2(T(3.1)) == 4.0);
819 assert(nextPow2(T(4.0)) == 8.0);
820 assert(nextPow2(T(0.25)) == 0.5);
822 assert(nextPow2(T(-2.0)) == -4.0);
823 assert(nextPow2(T(-2.1)) == -4.0);
824 assert(nextPow2(T(-3.1)) == -4.0);
825 assert(nextPow2(T(-4.0)) == -8.0);
826 assert(nextPow2(T(-0.25)) == -0.5);
828 assert(nextPow2(T
.max
) == 0);
829 assert(nextPow2(-T
.max
) == 0);
831 assert(nextPow2(T
.infinity
) == T
.infinity
);
832 assert(nextPow2(T
.init
).isNaN
);
836 // https://issues.dlang.org/show_bug.cgi?id=15973
837 @safe @nogc pure nothrow unittest
839 assert(nextPow2(uint.max
/ 2) == uint.max
/ 2 + 1);
840 assert(nextPow2(uint.max
/ 2 + 2) == 0);
841 assert(nextPow2(int.max
/ 2) == int.max
/ 2 + 1);
842 assert(nextPow2(int.max
/ 2 + 2) == 0);
843 assert(nextPow2(int.min
+ 1) == int.min
);
847 * Gives the last power of two before `val`. $(T) can be any built-in
854 * the last power of two before `val`
856 T
truncPow2(T
)(const T val
)
859 return powIntegralImpl
!(PowType
.floor
)(val
);
863 T
truncPow2(T
)(const T val
)
864 if (isFloatingPoint
!T
)
866 return powFloatingPointImpl
!(PowType
.floor
)(val
);
870 @safe @nogc pure nothrow unittest
872 assert(truncPow2(3) == 2);
873 assert(truncPow2(4) == 4);
874 assert(truncPow2(10) == 8);
875 assert(truncPow2(4000) == 2048);
877 assert(truncPow2(-5) == -4);
878 assert(truncPow2(-20) == -16);
880 assert(truncPow2(uint.max
) == int.max
+ 1);
881 assert(truncPow2(uint.min
) == 0);
882 assert(truncPow2(ulong.max
) == long.max
+ 1);
883 assert(truncPow2(ulong.min
) == 0);
885 assert(truncPow2(int.max
) == (int.max
/ 2) + 1);
886 assert(truncPow2(int.min
) == int.min
);
887 assert(truncPow2(long.max
) == (long.max
/ 2) + 1);
888 assert(truncPow2(long.min
) == long.min
);
892 @safe @nogc pure nothrow unittest
894 assert(truncPow2(2.1) == 2.0);
895 assert(truncPow2(7.0) == 4.0);
896 assert(truncPow2(-1.9) == -1.0);
897 assert(truncPow2(0.24) == 0.125);
898 assert(truncPow2(-7.0) == -4.0);
900 assert(truncPow2(double.infinity
) == double.infinity
);
903 @safe @nogc pure nothrow unittest
905 assert(truncPow2(ubyte(3)) == 2);
906 assert(truncPow2(ubyte(4)) == 4);
907 assert(truncPow2(ubyte(10)) == 8);
909 assert(truncPow2(byte(3)) == 2);
910 assert(truncPow2(byte(4)) == 4);
911 assert(truncPow2(byte(10)) == 8);
913 assert(truncPow2(ushort(3)) == 2);
914 assert(truncPow2(ushort(4)) == 4);
915 assert(truncPow2(ushort(10)) == 8);
916 assert(truncPow2(ushort(4000)) == 2048);
918 assert(truncPow2(short(3)) == 2);
919 assert(truncPow2(short(4)) == 4);
920 assert(truncPow2(short(10)) == 8);
921 assert(truncPow2(short(4000)) == 2048);
924 @safe @nogc pure nothrow unittest
926 foreach (ulong i
; 1 .. 62)
928 assert(truncPow2(2UL << i
) == 2UL << i
);
929 assert(truncPow2((2UL << i
) + 1) == 2UL << i
);
930 assert(truncPow2((2UL << i
) - 1) == 1UL << i
);
931 assert(truncPow2((2UL << i
) - (2UL<<(i
-1))) == 1UL << i
);
935 @safe @nogc pure nothrow unittest
937 import std
.math
.traits
: isNaN
;
938 import std
.meta
: AliasSeq
;
940 static foreach (T
; AliasSeq
!(float, double, real))
942 assert(truncPow2(T(0.0)) == 0.0);
944 assert(truncPow2(T(4.0)) == 4.0);
945 assert(truncPow2(T(2.1)) == 2.0);
946 assert(truncPow2(T(3.5)) == 2.0);
947 assert(truncPow2(T(7.0)) == 4.0);
948 assert(truncPow2(T(0.24)) == 0.125);
950 assert(truncPow2(T(-2.0)) == -2.0);
951 assert(truncPow2(T(-2.1)) == -2.0);
952 assert(truncPow2(T(-3.1)) == -2.0);
953 assert(truncPow2(T(-7.0)) == -4.0);
954 assert(truncPow2(T(-0.24)) == -0.125);
956 assert(truncPow2(T
.infinity
) == T
.infinity
);
957 assert(truncPow2(T
.init
).isNaN
);
968 private T
powIntegralImpl(PowType type
, T
)(T val
)
970 import core
.bitop
: bsr;
972 if (val
== 0 ||
(type
== PowType
.ceil
&& (val
> T
.max
/ 2 || val
== T
.min
)))
976 static if (isSigned
!T
)
977 return cast() cast(T
) (val
< 0 ?
-(T(1) << bsr(0 - val
) + type
) : T(1) << bsr(val
) + type
);
979 return cast() cast(T
) (T(1) << bsr(val
) + type
);
983 private T
powFloatingPointImpl(PowType type
, T
)(T x
)
985 import std
.math
.traits
: copysign
, isFinite
;
986 import std
.math
.exponential
: frexp
;
995 auto y
= frexp(x
, exp
);
997 static if (type
== PowType
.ceil
)
998 y
= core
.math
.ldexp(cast(T
) 0.5, exp
+ 1);
1000 y
= core
.math
.ldexp(cast(T
) 0.5, exp
);