1 /** Additions to $(STDMODULE _math). 2 3 Copyright: Denis Shelomovskij 2011-2012 4 5 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0). 6 7 Authors: Denis Shelomovskij 8 */ 9 module unstd.math; 10 11 12 public import std.math; 13 14 import core.bitop: bsr; 15 16 17 @safe pure nothrow @nogc: 18 19 20 /** 21 Returns $(D true) iff $(D n) is a power of 2. 22 23 Preconditions: 24 $(D n) must be non-zero. 25 */ 26 bool isPowerOf2(in size_t n) 27 in { assert(n > 0); } 28 body { return !((n - 1) & n); } 29 30 unittest 31 { 32 static assert( isPowerOf2(1)); 33 static assert( isPowerOf2(2)); 34 static assert(!isPowerOf2(3)); 35 static assert( isPowerOf2(4)); 36 static assert(!isPowerOf2(5)); 37 } 38 39 40 /** 41 Returns largest power of 2 which <= $(D n). 42 43 Preconditions: 44 $(D n) must be non-zero. 45 */ 46 size_t roundDownToPowerOf2(in size_t n) 47 in { assert(n > 0); } 48 body { return 1 << bsr(n); } 49 50 unittest 51 { 52 alias down = roundDownToPowerOf2; 53 static assert(!__traits(compiles, { enum e = down(0); })); 54 static assert(down(1) == 1); 55 static assert(down(2) == 2 && down(3) == 2); 56 static assert(down(4) == 4 && down(5) == 4); 57 static assert(down(6) == 4 && down(7) == 4); 58 static assert(down(8) == 8 && down(9) == 8); 59 } 60 61 62 /** 63 Returns smallest power of 2 which >= $(D n). 64 65 Preconditions: 66 $(D n) must be non-zero. 67 */ 68 size_t roundUpToPowerOf2(in size_t n) 69 in { assert(n > 0); } 70 body { return 1 << (bsr(n) + !isPowerOf2(n)); } 71 72 unittest 73 { 74 alias up = roundUpToPowerOf2; 75 static assert(!__traits(compiles, { enum e = up(0); })); 76 static assert(up(1) == 1); 77 static assert(up(2) == 2); 78 static assert(up(3) == 4 && up(4) == 4); 79 static assert(up(5) == 8 && up(6) == 8); 80 static assert(up(7) == 8 && up(8) == 8); 81 } 82 83 84 /** 85 Returns the base-2 logarithm of largest power of 2 which <= $(D n). 86 87 Preconditions: 88 $(D n) must be non-zero. 89 */ 90 ubyte log2RoundedDown(in size_t n) 91 in { assert(n > 0); } 92 body { return cast(ubyte) bsr(n); } 93 94 unittest 95 { 96 static assert(log2RoundedDown(1) == 0); 97 static assert(log2RoundedDown(1023) == 9); 98 static assert(log2RoundedDown(1024) == 10); 99 static assert(log2RoundedDown(1025) == 10); 100 } 101 102 103 /** 104 Returns the base-2 logarithm of smallest power of 2 which >= $(D n). 105 106 Preconditions: 107 $(D n) must be non-zero. 108 */ 109 ubyte log2RoundedUp(in size_t n) 110 in { assert(n > 0); } 111 body { return cast(ubyte) (bsr(n) + !isPowerOf2(n)); } 112 113 unittest 114 { 115 static assert(log2RoundedUp(1) == 0); 116 static assert(log2RoundedUp(1023) == 10); 117 static assert(log2RoundedUp(1024) == 10); 118 static assert(log2RoundedUp(1025) == 11); 119 } 120 121 122 /** 123 Aligns $(D n) up or down. 124 125 Preconditions: 126 $(D alignment) must be power of 2. 127 */ 128 size_t alignDown(in size_t alignment, in size_t n) 129 in { assert(isPowerOf2(alignment)); } 130 body 131 { 132 return n & ~(alignment - 1); // alignment - 1: 0b11, 0b111, ... 133 } 134 135 /// ditto 136 size_t alignDown(size_t alignment)(in size_t n) if(isPowerOf2(alignment)) 137 { return .alignDown(alignment, n); } 138 139 /// ditto 140 size_t alignUp(in size_t alignment, in size_t n) 141 in { assert(isPowerOf2(alignment)); } 142 body 143 { 144 return alignDown(alignment, n + alignment - 1); 145 } 146 147 /// ditto 148 size_t alignUp(size_t alignment)(in size_t n) if(isPowerOf2(alignment)) 149 { return .alignUp(alignment, n); } 150 151 /** 152 Aligns $(D n) up or down. 153 154 Preconditions: 155 $(D alignment) must be power of 2. 156 */ 157 bool isAligned(in size_t alignment, in size_t n) 158 in { assert(isPowerOf2(alignment)); } 159 body 160 { 161 return !(n & (alignment - 1)); // alignment - 1: 0b11, 0b111, ... 162 } 163 164 /// ditto 165 bool isAligned(size_t alignment)(in size_t n) if(isPowerOf2(alignment)) 166 { return .isAligned(alignment, n); } 167 168 unittest 169 { 170 import unstd.generictuple; 171 172 foreach(f; GenericTuple!(alignDown, alignUp, isAligned)) 173 { 174 static assert(!__traits(compiles, f!0(1))); 175 static assert(!__traits(compiles, { enum e = f(0, 1); })); 176 } 177 178 foreach(n; iotaTuple!5) 179 { 180 foreach(f; GenericTuple!(alignDown, alignUp)) 181 { 182 static assert(f!1(n) == n); 183 static assert(f(1, n) == n); 184 } 185 static assert(isAligned!1(n)); 186 static assert(isAligned(1, n)); 187 } 188 189 foreach(alignment; expressionTuple!(2, 4, 8, 16)) 190 { 191 static assert(!__traits(compiles, alignDown!(alignment + 1)(1))); 192 static assert(!__traits(compiles, alignUp!(alignment + 1)(1))); 193 194 alias down = alignDown!alignment; 195 alias up = alignUp!alignment; 196 alias aligned = isAligned!alignment; 197 static assert(down(0) == 0 && up(0) == 0 && aligned(0)); 198 199 static assert(down(1) == 0); 200 static assert(down(alignment - 1) == 0); 201 static assert(down(alignment) == alignment); 202 static assert(down(alignment + 1) == alignment); 203 204 static assert(up(1) == alignment); 205 static assert(up(alignment - 1) == alignment); 206 static assert(up(alignment) == alignment); 207 static assert(up(alignment + 1) == alignment * 2); 208 209 static assert(!aligned(1)); 210 static assert(!aligned(alignment - 1)); 211 static assert( aligned(alignment)); 212 static assert(!aligned(alignment + 1)); 213 } 214 215 static assert(alignDown!2(size_t.max) == size_t.max - 1); 216 static assert(alignDown!16(size_t.max) == size_t.max - 15); 217 static assert(alignUp!2(size_t.max - 1) == size_t.max - 1); 218 static assert(alignUp!2(size_t.max) == 0); 219 static assert(!isAligned!2(size_t.max)); 220 static assert( isAligned!16(size_t.max - 15)); 221 }