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 T rangeIntersection(T)(T a0, T a1, T b0, T b1) 47 { 48 import std.algorithm.comparison : min, max; 49 50 auto x0 = max(a0, b0); 51 auto x1 = min(a1, b1); 52 return x0 < x1 ? x1 - x0 : 0; 53 } 54 55 unittest 56 { 57 assert(rangeIntersection(0, 2, 1, 3) == 1); 58 assert(rangeIntersection(0, 1, 2, 3) == 0); 59 } 60 61 template unary(char op) 62 { 63 T unary(T)(T value) 64 { 65 // Silence DMD 2.078.0 warning about integer promotion rules 66 // https://dlang.org/changelog/2.078.0.html#fix16997 67 static if ((op == '-' || op == '+' || op == '~') && is(T : int)) 68 alias CastT = int; 69 else 70 alias CastT = T; 71 return mixin(`cast(T)` ~ op ~ `cast(CastT)value`); 72 } 73 } 74 75 /// Like the ~ operator, but without int-promotion. 76 alias flipBits = unary!'~'; 77 78 unittest 79 { 80 ubyte b = 0x80; 81 auto b2 = b.flipBits; 82 assert(b2 == 0x7F); 83 static assert(is(typeof(b2) == ubyte)); 84 } 85 86 T swapBytes(T)(T b) 87 { 88 import core.bitop : bswap; 89 static if (b.sizeof == 1) 90 return b; 91 else 92 static if (b.sizeof == 2) 93 return cast(T)((b >> 8) | (b << 8)); 94 else 95 static if (b.sizeof == 4) 96 return bswap(b); 97 else 98 static assert(false, "Don't know how to bswap " ~ T.stringof); 99 } 100 101 bool isPowerOfTwo(T)(T x) { return (x & (x-1)) == 0; } 102 T roundUpToPowerOfTwo(T)(T x) { return nextPowerOfTwo(x-1); } 103 T nextPowerOfTwo(T)(T x) 104 { 105 x |= x >> 1; 106 x |= x >> 2; 107 x |= x >> 4; 108 static if (T.sizeof > 1) 109 x |= x >> 8; 110 static if (T.sizeof > 2) 111 x |= x >> 16; 112 static if (T.sizeof > 4) 113 x |= x >> 32; 114 return x + 1; 115 } 116 117 /// Integer log2. 118 ubyte ilog2(T)(T n) 119 { 120 ubyte result = 0; 121 while (n >>= 1) 122 result++; 123 return result; 124 } 125 126 unittest 127 { 128 assert(ilog2(0) == 0); 129 assert(ilog2(1) == 0); 130 assert(ilog2(2) == 1); 131 assert(ilog2(3) == 1); 132 assert(ilog2(4) == 2); 133 } 134 135 /// Returns the number of bits needed to 136 /// store a number up to n (inclusive). 137 ubyte bitsFor(T)(T n) 138 { 139 return cast(ubyte)(ilog2(n)+1); 140 } 141 142 unittest 143 { 144 assert(bitsFor( int.max) == 31); 145 assert(bitsFor(uint.max) == 32); 146 } 147 148 /// Get the smallest built-in unsigned integer type 149 /// that can store this many bits of data. 150 template TypeForBits(uint bits) 151 { 152 static if (bits <= 8) 153 alias TypeForBits = ubyte; 154 else 155 static if (bits <= 16) 156 alias TypeForBits = ushort; 157 else 158 static if (bits <= 32) 159 alias TypeForBits = uint; 160 else 161 static if (bits <= 64) 162 alias TypeForBits = ulong; 163 else 164 static assert(false, "No integer type big enough for " ~ bits.stringof ~ " bits"); 165 } 166 167 static assert(is(TypeForBits!7 == ubyte)); 168 static assert(is(TypeForBits!8 == ubyte)); 169 static assert(is(TypeForBits!9 == ushort)); 170 static assert(is(TypeForBits!64 == ulong)); 171 static assert(!is(TypeForBits!65)); 172 173 void minimize(T, Args...)(ref T v, Args args) 174 if (is(typeof({ import std.algorithm.comparison : min; v = min(v, args); }))) 175 { 176 import std.algorithm.comparison : min; 177 v = min(v, args); 178 } 179 180 void maximize(T, Args...)(ref T v, Args args) 181 if (is(typeof({ import std.algorithm.comparison : max; v = max(v, args); }))) 182 { 183 import std.algorithm.comparison : max; 184 v = max(v, args); 185 } 186 187 unittest 188 { 189 int i = 5; 190 i.minimize(2); assert(i == 2); 191 i.minimize(5); assert(i == 2); 192 i.maximize(5); assert(i == 5); 193 i.maximize(2); assert(i == 5); 194 }