irox_tools/primitives/
f64.rs1use crate::{ToF64, ToSigned, WrappingSub};
10
11#[must_use]
22pub fn min_max(iter: &[f64]) -> (f64, f64) {
23 let mut min = f64::MAX;
24 let mut max = f64::MIN;
25
26 for val in iter {
27 min = min.min(*val);
28 max = max.max(*val);
29 }
30
31 (min, max)
32}
33
34pub trait FloatExt {
35 type Type;
36 type Size;
37 fn trunc(self) -> Self::Type;
38 fn fract(self) -> Self::Type;
39 fn abs(self) -> Self::Type;
40 fn round(self) -> Self::Type;
41 fn floor(self) -> Self::Type;
42 fn ceil(self) -> Self::Type;
43 fn signum(self) -> Self::Type;
44
45 fn exp(self) -> Self::Type;
46 fn ln(self) -> Self::Type;
47
48 fn powi(self, val: i32) -> Self::Type;
49 fn powf(self, val: Self::Type) -> Self::Type;
50
51 fn sqrt(self) -> Self::Type;
52 fn to_bits(self) -> Self::Size;
53 fn exponent(self) -> u16;
54 fn significand(self) -> Self::Size;
55}
56
57#[cfg(not(feature = "std"))]
58impl FloatExt for f64 {
59 type Type = f64;
60 type Size = u64;
61
62 fn trunc(self) -> f64 {
66 (self as u64) as f64
67 }
68
69 fn fract(self) -> f64 {
70 self - self.trunc()
71 }
72
73 fn abs(self) -> f64 {
76 f64::from_bits(self.to_bits() & 0x7FFF_FFFF_FFFF_FFFFu64)
77 }
78
79 fn round(self) -> f64 {
80 (self + 0.5 * self.signum()).trunc()
81 }
82
83 fn floor(self) -> f64 {
84 if self.is_sign_negative() {
85 return (self - 1.0).trunc();
86 }
87 self.trunc()
88 }
89
90 fn ceil(self) -> f64 {
91 if self.is_sign_positive() {
92 return (self + 1.0).trunc();
93 }
94 self.trunc()
95 }
96
97 fn signum(self) -> f64 {
98 if self.is_nan() {
99 return f64::NAN;
100 }
101 if self.is_sign_negative() {
102 return -1.0;
103 }
104 1.0
105 }
106
107 fn exp(self) -> Self::Type {
110 if self.is_nan() || self.is_infinite() {
111 return self;
112 }
113 let mut out = 1.0;
114 let i = self;
115 let mut idx = 1;
116 let mut next = self;
117
118 while next.abs() != 0.0 {
119 out += next;
120 idx += 1;
121 next *= i / idx as Self::Type;
122 }
123
124 out
125 }
126
127 fn ln(self) -> Self::Type {
130 if !self.is_normal() {
131 return self;
132 }
133 let z = self;
134 if z == 0. {
135 return 1.;
136 } else if z < 0. {
137 return f64::NAN;
138 }
139 let iter = (z - 1.) / (z + 1.);
140 let mut out = 0.0;
141 let mut next = 2.0 * iter;
142 let mut idx = 1.0;
143 let mut base = iter;
144 while next != 0.0 {
145 out += next;
146 idx += 2.0;
147 base *= iter * iter;
148 next = 2.0 * base / idx;
149 }
150 out
151 }
152
153 fn powf(self, a: Self::Type) -> Self::Type {
156 if !self.is_normal() {
157 return self;
158 }
159 let z = self;
160
161 (a * z.ln()).exp()
162 }
163
164 fn powi(self, val: i32) -> Self::Type {
166 if !self.is_normal() {
167 return self;
168 }
169 let mut out = self;
170 let i = self;
171 for _ in 0..val.abs() {
172 out *= i;
173 }
174 out
175 }
176
177 fn sqrt(self) -> Self::Type {
178 self.powf(0.5)
179 }
180
181 fn to_bits(self) -> Self::Size {
182 f64::to_bits(self)
183 }
184
185 fn exponent(self) -> u16 {
186 ((self.to_bits() >> 52) & 0x7FF) as u16
187 }
188
189 fn significand(self) -> Self::Size {
190 self.to_bits() & 0xF_FFFF_FFFF_FFFF
191 }
192}
193
194#[cfg(feature = "std")]
195impl FloatExt for f64 {
196 type Type = f64;
197 type Size = u64;
198
199 fn trunc(self) -> Self::Type {
200 f64::trunc(self)
201 }
202
203 fn fract(self) -> Self::Type {
204 f64::fract(self)
205 }
206
207 fn abs(self) -> Self::Type {
208 f64::abs(self)
209 }
210
211 fn round(self) -> Self::Type {
212 f64::round(self)
213 }
214
215 fn floor(self) -> Self::Type {
216 f64::floor(self)
217 }
218
219 fn ceil(self) -> Self::Type {
220 f64::ceil(self)
221 }
222
223 fn signum(self) -> Self::Type {
224 f64::signum(self)
225 }
226
227 fn exp(self) -> Self::Type {
228 f64::exp(self)
229 }
230
231 fn ln(self) -> Self::Type {
232 f64::ln(self)
233 }
234
235 fn powi(self, val: i32) -> Self::Type {
236 f64::powi(self, val)
237 }
238
239 fn powf(self, val: Self::Type) -> Self::Type {
240 f64::powf(self, val)
241 }
242
243 fn sqrt(self) -> Self::Type {
244 f64::sqrt(self)
245 }
246
247 fn to_bits(self) -> Self::Size {
248 f64::to_bits(self)
249 }
250
251 fn exponent(self) -> u16 {
252 ((self.to_bits() >> 52) & 0x7FF) as u16
253 }
254
255 fn significand(self) -> Self::Size {
256 self.to_bits() & 0xF_FFFF_FFFF_FFFF
257 }
258}
259
260impl WrappingSub for f64 {
261 fn wrapping_sub(&self, rhs: Self) -> Self {
262 self - rhs
263 }
264}
265impl ToF64 for f64 {
266 fn to_f64(&self) -> f64 {
267 *self
268 }
269}
270impl ToSigned for f64 {
271 type Output = f64;
272
273 fn to_signed(self) -> Self::Output {
274 self
275 }
276 fn negative_one() -> Self::Output {
277 -1.
278 }
279}
280
281#[cfg(test)]
282mod tests {
283 #[test]
284 pub fn test_ln() {
285 assert_eq_eps!(0.0, crate::f64::FloatExt::ln(1.0f64), 1e-16);
286 assert_eq_eps!(1.0, crate::f64::FloatExt::ln(core::f64::consts::E), 1e-15);
287 assert_eq_eps!(4.605170185988092, crate::f64::FloatExt::ln(100f64), 1e-13);
288 assert_eq_eps!(
289 11.090339630053647,
290 crate::f64::FloatExt::ln(u16::MAX as f64),
291 1e-11
292 );
293 }
294
295 #[test]
296 pub fn test_exp() {
297 assert_eq_eps!(1.0, crate::f64::FloatExt::exp(0.0f64), 1e-16);
298 assert_eq_eps!(
299 core::f64::consts::E,
300 crate::f64::FloatExt::exp(1.0f64),
301 1e-15
302 );
303 assert_eq_eps!(7.38905609893065, crate::f64::FloatExt::exp(2.0f64), 1e-14);
304 assert_eq_eps!(
305 15.154262241479262,
306 crate::f64::FloatExt::exp(core::f64::consts::E),
307 1e-15
308 );
309 }
310
311 #[test]
312 pub fn test_sqrt() {
313 assert_eq!(2., crate::f64::FloatExt::sqrt(4.0f64));
314 }
315}