v / vlib / math
Raw file | 134 loc (126 sloc) | 3.01 KB | Latest commit hash 017ace6ea
1module 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
9pub 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
30pub 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
40pub 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
54pub 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`
80pub 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
113pub 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}