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 
18 /// ditto
19 bool isPow2A(T)(T x) if (isIntegral!T)
20 {
21     return x && !(x & (x - 1));
22 }
23 
24 /// ditto
25 bool isPow2B(T)(T x) if (isIntegral!T)
26 {
27     return (x & -x) > (x - 1);
28 }
29 
30 bool isPow2D(T)(T x) if (isIntegral!T)
31 {
32     return (x > 0) && !(x & (x - 1));
33 }
34 
35 /// ditto, avoids a jump instruction.
36 bool isPow2E(T)(T x) if (isIntegral!T)
37 {
38     return (x > 0) & !(x & (x - 1));
39 }
40 
41 /// ditto
42 bool isPow2F(T)(T x) if (isIntegral!T)
43 {
44     return (x & -x) > (x >>> 1);
45 }
46 
47 ///
48 @safe pure nothrow @nogc unittest
49 {
50     import std.meta : AliasSeq;
51     foreach (fn; AliasSeq!(isPow2, isPow2A, isPow2D, isPow2E, isPow2F))
52     {
53         // run-time
54         assert(!fn(7));
55         assert(fn(8));
56         assert(!fn(9));
57 
58         // compile-time
59         static assert(!fn(7));
60         static assert(fn(8));
61         static assert(!fn(9));
62 
63         assert(!fn(0));
64         assert(fn(1));
65         assert(fn(2));
66         assert(!fn(3));
67         assert(fn(4));
68         assert(!fn(5));
69         assert(!fn(6));
70         assert(!fn(7));
71         assert(fn(8));
72     }
73 }
74 
75 /** Check if `x` is an exact (binary) power of 2, except when `x` is zero then
76  * zero is returned.
77  *
78  * See_Also: http://forum.dlang.org/thread/zumhmosfkvwjymjhmtlt@forum.dlang.org#post-fvnmurrctavpfkunssdf:40forum.dlang.org
79  * See_Also: http://forum.dlang.org/post/hloonbgclzloqemycnth@forum.dlang.org
80 */
81 bool isPow2fast(T)(T x)
82 if (isUnsigned!T)
83 {
84     return (x & (x - 1)) == 0;
85 }
86 
87 @safe pure nothrow @nogc unittest
88 {
89     import std.meta : AliasSeq;
90     foreach (fn; AliasSeq!(isPow2fast))
91     {
92         // run-time
93         assert(!fn(7U));
94         assert(fn(8U));
95         assert(!fn(9U));
96 
97         // compile-time
98         static assert(!fn(7U));
99         static assert(fn(8U));
100         static assert(!fn(9U));
101 
102         assert(fn(1U));
103         assert(fn(2U));
104         assert(!fn(3U));
105         assert(fn(4U));
106         assert(!fn(5U));
107         assert(!fn(6U));
108         assert(!fn(7U));
109         assert(fn(8U));
110     }
111 }