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 @safe pure nothrow @nogc unittest
30 {
31     import std.meta : AliasSeq;
32     foreach (fn; AliasSeq!(isPow2, isPow2A, isPow2D, isPow2E, isPow2F))
33     {
34         // run-time
35         assert(!fn(7));
36         assert(fn(8));
37         assert(!fn(9));
38 
39         // compile-time
40         static assert(!fn(7));
41         static assert(fn(8));
42         static assert(!fn(9));
43 
44         assert(!fn(0));
45         assert(fn(1));
46         assert(fn(2));
47         assert(!fn(3));
48         assert(fn(4));
49         assert(!fn(5));
50         assert(!fn(6));
51         assert(!fn(7));
52         assert(fn(8));
53     }
54 }
55 
56 /** Check if `x` is an exact (binary) power of 2, except when `x` is zero then
57  * zero is returned.
58  *
59  * See_Also: http://forum.dlang.org/thread/zumhmosfkvwjymjhmtlt@forum.dlang.org#post-fvnmurrctavpfkunssdf:40forum.dlang.org
60  * See_Also: http://forum.dlang.org/post/hloonbgclzloqemycnth@forum.dlang.org
61 */
62 bool isPow2fast(T)(T x) if (isUnsigned!T) => (x & (x - 1)) == 0;
63 
64 @safe pure nothrow @nogc unittest
65 {
66     import std.meta : AliasSeq;
67     foreach (fn; AliasSeq!(isPow2fast))
68     {
69         // run-time
70         assert(!fn(7U));
71         assert(fn(8U));
72         assert(!fn(9U));
73 
74         // compile-time
75         static assert(!fn(7U));
76         static assert(fn(8U));
77         static assert(!fn(9U));
78 
79         assert(fn(1U));
80         assert(fn(2U));
81         assert(!fn(3U));
82         assert(fn(4U));
83         assert(!fn(5U));
84         assert(!fn(6U));
85         assert(!fn(7U));
86         assert(fn(8U));
87     }
88 }