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 public import std.algorithm : min, max, swap;
17 public import std.math;
18 import std.traits : Signed, Unsigned;
19 import core.bitop : bswap;
20 
21 typeof(Ta+Tb+Tc) bound(Ta, Tb, Tc)(Ta a, Tb b, Tc c) { return a<b?b:a>c?c:a; }
22 bool between(T)(T point, T a, T b) { return a <= point && point <= b; } /// Assumes points are sorted (was there a faster way?)
23 auto sqr(T)(T x) { return x*x; }
24 
25 void sort2(T)(ref T x, ref T y) { if (x > y) { T z=x; x=y; y=z; } }
26 
27 T itpl(T, U)(T low, T high, U r, U rLow, U rHigh)
28 {
29 	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));
30 }
31 
32 byte sign(T)(T x) { return x<0 ? -1 : x>0 ? 1 : 0; }
33 
34 int compare(T)(T a, T b)
35 {
36 	return a<b ? -1 : a>b ? 1 : 0;
37 }
38 
39 auto op(string OP, T...)(T args)
40 {
41 	auto result = args[0];
42 	foreach (arg; args[1..$])
43 		mixin("result" ~ OP ~ "=arg;");
44 	return result;
45 }
46 
47 auto sum(T...)(T args) { return op!"+"(args); }
48 auto average(T...)(T args) { return sum(args) / args.length; }
49 
50 T swapBytes(T)(T b)
51 {
52 	static if (b.sizeof == 1)
53 		return b;
54 	else
55 	static if (b.sizeof == 2)
56 		return cast(T)((b >> 8) | (b << 8));
57 	else
58 	static if (b.sizeof == 4)
59 		return bswap(b);
60 	else
61 		static assert(false, "Don't know how to bswap " ~ T.stringof);
62 }
63 
64 bool isPowerOfTwo(T)(T x) { return (x & (x-1)) == 0; }
65 T roundUpToPowerOfTwo(T)(T x) { return nextPowerOfTwo(x-1); }
66 T nextPowerOfTwo(T)(T x)
67 {
68 	x |= x >>  1;
69 	x |= x >>  2;
70 	x |= x >>  4;
71 	static if (T.sizeof > 1)
72 		x |= x >>  8;
73 	static if (T.sizeof > 2)
74 		x |= x >> 16;
75 	static if (T.sizeof > 4)
76 		x |= x >> 32;
77 	return x + 1;
78 }
79 
80 /// Integer log2.
81 ubyte ilog2(T)(T n)
82 {
83 	ubyte result = 0;
84 	while (n >>= 1)
85 		result++;
86 	return result;
87 }
88 
89 unittest
90 {
91 	assert(ilog2(0) == 0);
92 	assert(ilog2(1) == 0);
93 	assert(ilog2(2) == 1);
94 	assert(ilog2(3) == 1);
95 	assert(ilog2(4) == 2);
96 }
97 
98 /// Returns the number of bits needed to
99 /// store a number up to n (inclusive).
100 ubyte bitsFor(T)(T n)
101 {
102 	return cast(ubyte)(ilog2(n)+1);
103 }
104 
105 unittest
106 {
107 	assert(bitsFor( int.max) == 31);
108 	assert(bitsFor(uint.max) == 32);
109 }
110 
111 /// Get the smallest built-in unsigned integer type
112 /// that can store this many bits of data.
113 template TypeForBits(uint bits)
114 {
115 	static if (bits <= 8)
116 		alias TypeForBits = ubyte;
117 	else
118 	static if (bits <= 16)
119 		alias TypeForBits = ushort;
120 	else
121 	static if (bits <= 32)
122 		alias TypeForBits = uint;
123 	else
124 	static if (bits <= 64)
125 		alias TypeForBits = ulong;
126 	else
127 		static assert(false, "No integer type big enough for " ~ bits.stringof ~ " bits");
128 }
129 
130 static assert(is(TypeForBits!7 == ubyte));
131 static assert(is(TypeForBits!8 == ubyte));
132 static assert(is(TypeForBits!9 == ushort));
133 static assert(is(TypeForBits!64 == ulong));
134 static assert(!is(TypeForBits!65));