1 | module math |
2 | |
3 | // floor returns the greatest integer value less than or equal to x. |
4 | // |
5 | // special cases are: |
6 | // floor(±0) = ±0 |
7 | // floor(±inf) = ±inf |
8 | // floor(nan) = nan |
9 | pub fn floor(x f64) f64 { |
10 | if x == 0 || is_nan(x) || is_inf(x, 0) { |
11 | return x |
12 | } |
13 | if x < 0 { |
14 | mut d, fract := modf(-x) |
15 | if fract != 0.0 { |
16 | d = d + 1 |
17 | } |
18 | return -d |
19 | } |
20 | d, _ := modf(x) |
21 | return d |
22 | } |
23 | |
24 | // ceil returns the least integer value greater than or equal to x. |
25 | // |
26 | // special cases are: |
27 | // ceil(±0) = ±0 |
28 | // ceil(±inf) = ±inf |
29 | // ceil(nan) = nan |
30 | pub fn ceil(x f64) f64 { |
31 | return -floor(-x) |
32 | } |
33 | |
34 | // trunc returns the integer value of x. |
35 | // |
36 | // special cases are: |
37 | // trunc(±0) = ±0 |
38 | // trunc(±inf) = ±inf |
39 | // trunc(nan) = nan |
40 | pub fn trunc(x f64) f64 { |
41 | if x == 0 || is_nan(x) || is_inf(x, 0) { |
42 | return x |
43 | } |
44 | d, _ := modf(x) |
45 | return d |
46 | } |
47 | |
48 | // round returns the nearest integer, rounding half away from zero. |
49 | // |
50 | // special cases are: |
51 | // round(±0) = ±0 |
52 | // round(±inf) = ±inf |
53 | // round(nan) = nan |
54 | pub fn round(x f64) f64 { |
55 | if x == 0 || is_nan(x) || is_inf(x, 0) { |
56 | return x |
57 | } |
58 | // Largest integer <= x |
59 | mut y := floor(x) // Fractional part |
60 | mut r := x - y // Round up to nearest. |
61 | if r > 0.5 { |
62 | unsafe { |
63 | goto rndup |
64 | } |
65 | } |
66 | // Round to even |
67 | if r == 0.5 { |
68 | r = y - 2.0 * floor(0.5 * y) |
69 | if r == 1.0 { |
70 | rndup: |
71 | y += 1.0 |
72 | } |
73 | } |
74 | // Else round down. |
75 | return y |
76 | } |
77 | |
78 | // Returns the rounded float, with sig_digits of precision. |
79 | // i.e `assert round_sig(4.3239437319748394,6) == 4.323944` |
80 | pub fn round_sig(x f64, sig_digits int) f64 { |
81 | mut ret_str := '${x}' |
82 | |
83 | match sig_digits { |
84 | 0 { ret_str = '${x:0.0f}' } |
85 | 1 { ret_str = '${x:0.1f}' } |
86 | 2 { ret_str = '${x:0.2f}' } |
87 | 3 { ret_str = '${x:0.3f}' } |
88 | 4 { ret_str = '${x:0.4f}' } |
89 | 5 { ret_str = '${x:0.5f}' } |
90 | 6 { ret_str = '${x:0.6f}' } |
91 | 7 { ret_str = '${x:0.7f}' } |
92 | 8 { ret_str = '${x:0.8f}' } |
93 | 9 { ret_str = '${x:0.9f}' } |
94 | 10 { ret_str = '${x:0.10f}' } |
95 | 11 { ret_str = '${x:0.11f}' } |
96 | 12 { ret_str = '${x:0.12f}' } |
97 | 13 { ret_str = '${x:0.13f}' } |
98 | 14 { ret_str = '${x:0.14f}' } |
99 | 15 { ret_str = '${x:0.15f}' } |
100 | 16 { ret_str = '${x:0.16f}' } |
101 | else { ret_str = '${x}' } |
102 | } |
103 | |
104 | return ret_str.f64() |
105 | } |
106 | |
107 | // round_to_even returns the nearest integer, rounding ties to even. |
108 | // |
109 | // special cases are: |
110 | // round_to_even(±0) = ±0 |
111 | // round_to_even(±inf) = ±inf |
112 | // round_to_even(nan) = nan |
113 | pub fn round_to_even(x f64) f64 { |
114 | mut bits := f64_bits(x) |
115 | mut e_ := (bits >> shift) & mask |
116 | if e_ >= bias { |
117 | // round abs(x) >= 1. |
118 | // - Large numbers without fractional components, infinity, and nan are unchanged. |
119 | // - Add 0.499.. or 0.5 before truncating depending on whether the truncated |
120 | // number is even or odd (respectively). |
121 | half_minus_ulp := u64(u64(1) << (shift - 1)) - 1 |
122 | e_ -= u64(bias) |
123 | bits += (half_minus_ulp + (bits >> (shift - e_)) & 1) >> e_ |
124 | bits &= frac_mask >> e_ |
125 | bits ^= frac_mask >> e_ |
126 | } else if e_ == bias - 1 && bits & frac_mask != 0 { |
127 | // round 0.5 < abs(x) < 1. |
128 | bits = bits & sign_mask | uvone // +-1 |
129 | } else { |
130 | // round abs(x) <= 0.5 including denormals. |
131 | bits &= sign_mask // +-0 |
132 | } |
133 | return f64_from_bits(bits) |
134 | } |