/
numeric.d
98 lines (81 loc) · 2.15 KB
/
numeric.d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
/++
+ Functions and templates that do numeric calculations or other manipulation,
+ in some way or another.
+/
module lu.numeric;
private:
import std.typecons : Flag, No, Yes;
public:
@safe:
// getMultipleOf
/++
+ Given a number, calculate the largest multiple of `n` needed to reach that number.
+
+ It rounds up, and if supplied `Yes.alwaysOneUp` it will always overshoot.
+ This is good for when calculating format pattern widths.
+
+ Example:
+ ---
+ immutable width = 15.getMultipleOf(4);
+ assert(width == 16);
+ immutable width2 = 16.getMultipleOf!(Yes.alwaysOneUp)(4);
+ assert(width2 == 20);
+ ---
+
+ Params:
+ oneUp = Whether or not to always overshoot.
+ num = Number to reach.
+ n = Base value to find a multiplier for.
+
+ Returns:
+ The multiple of `n` that reaches and possibly overshoots `num`.
+/
Number getMultipleOf(Flag!"alwaysOneUp" oneUp = No.alwaysOneUp, Number)
(const Number num, const int n) pure nothrow @nogc
in ((n > 0), "Cannot get multiple of 0 or negatives")
in ((num >= 0), "Cannot get multiples for a negative number")
do
{
if (num == 0) return 0;
if (num == n)
{
static if (oneUp)
{
return (n + 1);
}
else
{
return n;
}
}
immutable frac = (num / double(n));
immutable floor_ = cast(uint)frac;
static if (oneUp)
{
immutable mod = (floor_ + 1);
}
else
{
immutable mod = (floor_ == frac) ? floor_ : (floor_ + 1);
}
return cast(uint)(mod * n);
}
///
unittest
{
import std.conv : text;
immutable n1 = 15.getMultipleOf(4);
assert((n1 == 16), n1.text);
immutable n2 = 16.getMultipleOf!(Yes.alwaysOneUp)(4);
assert((n2 == 20), n2.text);
immutable n3 = 16.getMultipleOf(4);
assert((n3 == 16), n3.text);
immutable n4 = 0.getMultipleOf(5);
assert((n4 == 0), n4.text);
immutable n5 = 1.getMultipleOf(1);
assert((n5 == 1), n5.text);
immutable n6 = 1.getMultipleOf!(Yes.alwaysOneUp)(1);
assert((n6 == 2), n6.text);
immutable n7 = 5.getMultipleOf!(Yes.alwaysOneUp)(5);
assert((n7 == 6), n7.text);
}