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