v / vlib / math / floor.v
165 lines · 155 sloc · 3.72 KB · 952ae4d0d8eb07bd7770b288c3341d7ce454a5cc
Raw
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// floorf returns the greatest integer value less than or equal to x.
25//
26// special cases are:
27// floor(±0) = ±0
28// floor(±inf) = ±inf
29// floor(nan) = nan
30pub fn floorf(x f32) f32 {
31 // TODO
32 return f32(floor(f64(x)))
33 /*
34 if x == 0 || is_nan(x) || is_inf(x, 0) {
35 return x
36 }
37 if x < 0 {
38 mut d, fract := modf(-x)
39 if fract != 0.0 {
40 d = d + 1
41 }
42 return -d
43 }
44 d, _ := modf(x)
45 return d
46 */
47}
48
49// ceil returns the least integer value greater than or equal to x.
50//
51// special cases are:
52// ceil(±0) = ±0
53// ceil(±inf) = ±inf
54// ceil(nan) = nan
55pub fn ceil(x f64) f64 {
56 return -floor(-x)
57}
58
59// trunc returns the integer value of x.
60//
61// special cases are:
62// trunc(±0) = ±0
63// trunc(±inf) = ±inf
64// trunc(nan) = nan
65pub fn trunc(x f64) f64 {
66 if x == 0 || is_nan(x) || is_inf(x, 0) {
67 return x
68 }
69 d, _ := modf(x)
70 return d
71}
72
73// round returns the nearest integer, rounding half away from zero.
74//
75// special cases are:
76// round(±0) = ±0
77// round(±inf) = ±inf
78// round(nan) = nan
79pub fn round(x f64) f64 {
80 mut bits := f64_bits(x)
81 mut e_ := (bits >> shift) & mask
82 if e_ < bias {
83 // Round abs(x) < 1 including denormals.
84 bits &= sign_mask // +-0
85 if e_ == bias - 1 {
86 bits |= uvone // +-1
87 }
88 } else if e_ < bias + shift {
89 // Round any abs(x) >= 1 containing a fractional component [0,1).
90 //
91 // Numbers with larger exponents are returned unchanged since they
92 // must be either an integer, infinity, or NaN.
93 half := u64(1) << (shift - 1)
94 e_ -= bias
95 bits += half >> e_
96 bits &= ~(frac_mask >> e_)
97 }
98 return f64_from_bits(bits)
99}
100
101// Returns the rounded float, with sig_digits of precision.
102// i.e `assert round_sig(4.3239437319748394,6) == 4.323944`
103pub fn round_sig(x f64, sig_digits int) f64 {
104 mut ret_str := '${x}'
105
106 match sig_digits {
107 0 { ret_str = '${x:0.0f}' }
108 1 { ret_str = '${x:0.1f}' }
109 2 { ret_str = '${x:0.2f}' }
110 3 { ret_str = '${x:0.3f}' }
111 4 { ret_str = '${x:0.4f}' }
112 5 { ret_str = '${x:0.5f}' }
113 6 { ret_str = '${x:0.6f}' }
114 7 { ret_str = '${x:0.7f}' }
115 8 { ret_str = '${x:0.8f}' }
116 9 { ret_str = '${x:0.9f}' }
117 10 { ret_str = '${x:0.10f}' }
118 11 { ret_str = '${x:0.11f}' }
119 12 { ret_str = '${x:0.12f}' }
120 13 { ret_str = '${x:0.13f}' }
121 14 { ret_str = '${x:0.14f}' }
122 15 { ret_str = '${x:0.15f}' }
123 16 { ret_str = '${x:0.16f}' }
124 else { ret_str = '${x}' }
125 }
126
127 return ret_str.f64()
128}
129
130// round_to_even returns the nearest integer, rounding ties to even.
131//
132// special cases are:
133// round_to_even(±0) = ±0
134// round_to_even(±inf) = ±inf
135// round_to_even(nan) = nan
136pub fn round_to_even(x f64) f64 {
137 mut bits := f64_bits(x)
138 mut e_ := (bits >> shift) & mask
139 if e_ >= bias {
140 // round abs(x) >= 1.
141 // - Large numbers without fractional components, infinity, and nan are unchanged.
142 // - Add 0.499.. or 0.5 before truncating depending on whether the truncated
143 // number is even or odd (respectively).
144 half_minus_ulp := u64(u64(1) << (shift - 1)) - 1
145 e_ -= u64(bias)
146 bits += safe_shift(half_minus_ulp + safe_shift(bits, shift - e_) & 1, e_)
147 bits &= ~safe_shift(frac_mask, e_)
148 } else if e_ == bias - 1 && bits & frac_mask != 0 {
149 // round 0.5 < abs(x) < 1.
150 bits = bits & sign_mask | uvone // +-1
151 } else {
152 // round abs(x) <= 0.5 including denormals.
153 bits &= sign_mask // +-0
154 }
155 return f64_from_bits(bits)
156}
157
158@[inline]
159fn safe_shift(value u64, shift u64) u64 {
160 return if shift > u64(63) {
161 u64(0)
162 } else {
163 value >> shift
164 }
165}
166