1 /** 2 * Number stuff 3 * 4 * License: 5 * This Source Code Form is subject to the terms of 6 * the Mozilla Public License, v. 2.0. If a copy of 7 * the MPL was not distributed with this file, You 8 * can obtain one at http://mozilla.org/MPL/2.0/. 9 * 10 * Authors: 11 * Vladimir Panteleev <vladimir@thecybershadow.net> 12 */ 13 14 module ae.utils.math; 15 16 typeof(Ta+Tb+Tc) bound(Ta, Tb, Tc)(Ta a, Tb b, Tc c) { return a<b?b:a>c?c:a; } 17 bool between(T)(T point, T a, T b) { return a <= point && point <= b; } /// Assumes points are sorted (was there a faster way?) 18 auto sqr(T)(T x) { return x*x; } 19 20 void sort2(T)(ref T x, ref T y) { if (x > y) { T z=x; x=y; y=z; } } 21 22 T itpl(T, U)(T low, T high, U r, U rLow, U rHigh) 23 { 24 import std.traits : Signed; 25 return cast(T)(low + (cast(Signed!T)high-cast(Signed!T)low) * (cast(Signed!U)r - cast(Signed!U)rLow) / (cast(Signed!U)rHigh - cast(Signed!U)rLow)); 26 } 27 28 byte sign(T)(T x) { return x<0 ? -1 : x>0 ? 1 : 0; } 29 30 int compare(T)(T a, T b) 31 { 32 return a<b ? -1 : a>b ? 1 : 0; 33 } 34 35 auto op(string OP, T...)(T args) 36 { 37 auto result = args[0]; 38 foreach (arg; args[1..$]) 39 mixin("result" ~ OP ~ "=arg;"); 40 return result; 41 } 42 43 auto sum(T...)(T args) { return op!"+"(args); } 44 auto average(T...)(T args) { return sum(args) / args.length; } 45 46 template binary(string op) 47 { 48 auto binary(A, B)(auto ref A a, auto ref B b) { return mixin(`a` ~ op ~ `b`); } 49 } 50 alias eq = binary!"=="; 51 alias ne = binary!"!="; 52 alias lt = binary!"<"; 53 alias gt = binary!">"; 54 alias le = binary!"<="; 55 alias ge = binary!">="; 56 57 T rangeIntersection(T)(T a0, T a1, T b0, T b1) 58 { 59 import std.algorithm.comparison : min, max; 60 61 auto x0 = max(a0, b0); 62 auto x1 = min(a1, b1); 63 return x0 < x1 ? x1 - x0 : 0; 64 } 65 66 unittest 67 { 68 assert(rangeIntersection(0, 2, 1, 3) == 1); 69 assert(rangeIntersection(0, 1, 2, 3) == 0); 70 } 71 72 template unary(char op) 73 { 74 T unary(T)(T value) 75 { 76 // Silence DMD 2.078.0 warning about integer promotion rules 77 // https://dlang.org/changelog/2.078.0.html#fix16997 78 static if ((op == '-' || op == '+' || op == '~') && is(T : int)) 79 alias CastT = int; 80 else 81 alias CastT = T; 82 return mixin(`cast(T)` ~ op ~ `cast(CastT)value`); 83 } 84 } 85 86 /// Like the ~ operator, but without int-promotion. 87 alias flipBits = unary!'~'; 88 89 unittest 90 { 91 ubyte b = 0x80; 92 auto b2 = b.flipBits; 93 assert(b2 == 0x7F); 94 static assert(is(typeof(b2) == ubyte)); 95 } 96 97 T swapBytes(T)(T b) 98 { 99 import core.bitop : bswap; 100 static if (b.sizeof == 1) 101 return b; 102 else 103 static if (b.sizeof == 2) 104 return cast(T)((b >> 8) | (b << 8)); 105 else 106 static if (b.sizeof == 4) 107 return bswap(b); 108 else 109 static assert(false, "Don't know how to bswap " ~ T.stringof); 110 } 111 112 bool isPowerOfTwo(T)(T x) { return (x & (x-1)) == 0; } 113 T roundUpToPowerOfTwo(T)(T x) { return nextPowerOfTwo(x-1); } 114 T nextPowerOfTwo(T)(T x) 115 { 116 x |= x >> 1; 117 x |= x >> 2; 118 x |= x >> 4; 119 static if (T.sizeof > 1) 120 x |= x >> 8; 121 static if (T.sizeof > 2) 122 x |= x >> 16; 123 static if (T.sizeof > 4) 124 x |= x >> 32; 125 return x + 1; 126 } 127 128 /// Integer log2. 129 ubyte ilog2(T)(T n) 130 { 131 ubyte result = 0; 132 while (n >>= 1) 133 result++; 134 return result; 135 } 136 137 unittest 138 { 139 assert(ilog2(0) == 0); 140 assert(ilog2(1) == 0); 141 assert(ilog2(2) == 1); 142 assert(ilog2(3) == 1); 143 assert(ilog2(4) == 2); 144 } 145 146 /// Returns the number of bits needed to 147 /// store a number up to n (inclusive). 148 ubyte bitsFor(T)(T n) 149 { 150 return cast(ubyte)(ilog2(n)+1); 151 } 152 153 unittest 154 { 155 assert(bitsFor( int.max) == 31); 156 assert(bitsFor(uint.max) == 32); 157 } 158 159 /// Get the smallest built-in unsigned integer type 160 /// that can store this many bits of data. 161 template TypeForBits(uint bits) 162 { 163 static if (bits <= 8) 164 alias TypeForBits = ubyte; 165 else 166 static if (bits <= 16) 167 alias TypeForBits = ushort; 168 else 169 static if (bits <= 32) 170 alias TypeForBits = uint; 171 else 172 static if (bits <= 64) 173 alias TypeForBits = ulong; 174 else 175 static assert(false, "No integer type big enough for " ~ bits.stringof ~ " bits"); 176 } 177 178 static assert(is(TypeForBits!7 == ubyte)); 179 static assert(is(TypeForBits!8 == ubyte)); 180 static assert(is(TypeForBits!9 == ushort)); 181 static assert(is(TypeForBits!64 == ulong)); 182 static assert(!is(TypeForBits!65)); 183 184 void minimize(T, Args...)(ref T v, Args args) 185 if (is(typeof({ import std.algorithm.comparison : min; v = min(v, args); }))) 186 { 187 import std.algorithm.comparison : min; 188 v = min(v, args); 189 } 190 191 void maximize(T, Args...)(ref T v, Args args) 192 if (is(typeof({ import std.algorithm.comparison : max; v = max(v, args); }))) 193 { 194 import std.algorithm.comparison : max; 195 v = max(v, args); 196 } 197 198 unittest 199 { 200 int i = 5; 201 i.minimize(2); assert(i == 2); 202 i.minimize(5); assert(i == 2); 203 i.maximize(5); assert(i == 5); 204 i.maximize(2); assert(i == 5); 205 }