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