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