1 module nxt.math_ex;
2 
3 import std.traits : isIntegral, isUnsigned, isNumeric;
4 
5 /** Check if `x` is an exact (binary) power of 2.
6  *
7  * See_Also: http://forum.dlang.org/thread/zumhmosfkvwjymjhmtlt@forum.dlang.org#post-fvnmurrctavpfkunssdf:40forum.dlang.org
8  * See_Also: http://forum.dlang.org/post/hloonbgclzloqemycnth@forum.dlang.org
9 */
10 bool isPow2(T)(T x)
11 	if (isNumeric!T)
12 {
13 	import std.math : isPowerOf2; // https://github.com/dlang/phobos/pull/4327/files
14 	return isPowerOf2(x);
15 }
16 alias isPowerOf2 = isPow2;
17 /// ditto
18 bool isPow2A(T)(T x) if (isIntegral!T) => x && !(x & (x - 1));
19 /// ditto
20 bool isPow2B(T)(T x) if (isIntegral!T) => (x & -x) > (x - 1);
21 /// ditto
22 bool isPow2D(T)(T x) if (isIntegral!T) => (x > 0) && !(x & (x - 1));
23 /// ditto, avoids a jump instruction.
24 bool isPow2E(T)(T x) if (isIntegral!T) => (x > 0) & !(x & (x - 1));
25 /// ditto
26 bool isPow2F(T)(T x) if (isIntegral!T) => (x & -x) > (x >>> 1);
27 
28 ///
29 pure nothrow @safe @nogc unittest {
30 	import std.meta : AliasSeq;
31 	foreach (fn; AliasSeq!(isPow2, isPow2A, isPow2D, isPow2E, isPow2F))
32 	{
33 		// run-time
34 		assert(!fn(7));
35 		assert(fn(8));
36 		assert(!fn(9));
37 
38 		// compile-time
39 		static assert(!fn(7));
40 		static assert(fn(8));
41 		static assert(!fn(9));
42 
43 		assert(!fn(0));
44 		assert(fn(1));
45 		assert(fn(2));
46 		assert(!fn(3));
47 		assert(fn(4));
48 		assert(!fn(5));
49 		assert(!fn(6));
50 		assert(!fn(7));
51 		assert(fn(8));
52 	}
53 }
54 
55 /** Check if `x` is an exact (binary) power of 2, except when `x` is zero then
56  * zero is returned.
57  *
58  * See_Also: http://forum.dlang.org/thread/zumhmosfkvwjymjhmtlt@forum.dlang.org#post-fvnmurrctavpfkunssdf:40forum.dlang.org
59  * See_Also: http://forum.dlang.org/post/hloonbgclzloqemycnth@forum.dlang.org
60 */
61 bool isPow2fast(T)(T x) if (isUnsigned!T) => (x & (x - 1)) == 0;
62 
63 pure nothrow @safe @nogc unittest {
64 	import std.meta : AliasSeq;
65 	foreach (fn; AliasSeq!(isPow2fast))
66 	{
67 		// run-time
68 		assert(!fn(7U));
69 		assert(fn(8U));
70 		assert(!fn(9U));
71 
72 		// compile-time
73 		static assert(!fn(7U));
74 		static assert(fn(8U));
75 		static assert(!fn(9U));
76 
77 		assert(fn(1U));
78 		assert(fn(2U));
79 		assert(!fn(3U));
80 		assert(fn(4U));
81 		assert(!fn(5U));
82 		assert(!fn(6U));
83 		assert(!fn(7U));
84 		assert(fn(8U));
85 	}
86 }