1use crate::{FloatIsh, FromF64, One, PrimitiveMath, ToF64, ToSigned, WrappingSub, Zero};
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: PrimitiveMath {
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 fn clamp(self, min: Self, max: Self) -> Self::Type;
45
46 fn exp(self) -> Self::Type;
47 fn ln(self) -> Self::Type;
48 fn log10(self) -> Self::Type;
49
50 fn powi(self, val: i32) -> Self::Type;
51 fn powf(self, val: Self::Type) -> Self::Type;
52
53 fn sqrt(self) -> Self::Type;
54 fn to_bits(self) -> Self::Size;
55 fn exponent(self) -> u16;
56 fn significand(self) -> Self::Size;
57 fn sin(self) -> Self::Type;
58 fn cos(self) -> Self::Type;
59 fn tan(self) -> Self::Type;
60 fn atan(self) -> Self::Type;
61 fn atan2(self, o: Self) -> Self::Type;
62}
63#[allow(unused)]
64fn cordic_k(n: usize) -> f64 {
65 let mut k = 1.0;
66 let mut i = n;
67 let mut ik = 1.0;
68 while i > 0 {
69 k *= 1. / f64::sqrt(1. + ik);
70 ik /= 4.0;
71 i -= 1;
72 }
73 k
74}
75const CORDIC_K_64: f64 = 0.6072529350088814;
76const CORDIC_ITERS: usize = 64;
77const THETA_TABLE: [f64; CORDIC_ITERS] = [
78 core::f64::consts::FRAC_PI_4,
79 0.4636476090008061,
80 0.24497866312686414,
81 0.12435499454676144,
82 0.06241880999595735,
83 0.031239833430268277,
84 0.015623728620476831,
85 0.007812341060101111,
86 0.0039062301319669718,
87 0.0019531225164788188,
88 0.0009765621895593195,
89 0.0004882812111948983,
90 0.00024414062014936177,
91 0.00012207031189367021,
92 0.00006103515617420877,
93 0.000030517578115526096,
94 0.000015258789061315762,
95 0.00000762939453110197,
96 0.000003814697265606496,
97 0.000001907348632810187,
98 0.0000009536743164059608,
99 0.00000047683715820308884,
100 0.00000023841857910155797,
101 0.00000011920928955078068,
102 0.00000005960464477539055,
103 0.000000029802322387695303,
104 0.000000014901161193847655,
105 0.000000007450580596923828,
106 0.000000003725290298461914,
107 0.000000001862645149230957,
108 0.0000000009313225746154785,
109 0.0000000004656612873077393,
110 0.00000000023283064365386963,
111 0.00000000011641532182693481,
112 0.00000000005820766091346741,
113 0.000000000029103830456733704,
114 0.000000000014551915228366852,
115 0.000000000007275957614183426,
116 0.000000000003637978807091713,
117 0.0000000000018189894035458565,
118 0.0000000000009094947017729282,
119 0.0000000000004547473508864641,
120 0.00000000000022737367544323206,
121 0.00000000000011368683772161603,
122 0.00000000000005684341886080802,
123 0.00000000000002842170943040401,
124 0.000000000000014210854715202004,
125 0.000000000000007105427357601002,
126 0.000000000000003552713678800501,
127 0.0000000000000017763568394002505,
128 0.0000000000000008881784197001252,
129 0.0000000000000004440892098500626,
130 0.0000000000000002220446049250313,
131 0.00000000000000011102230246251565,
132 0.00000000000000005551115123125783,
133 0.000000000000000027755575615628914,
134 0.000000000000000013877787807814457,
135 0.000000000000000006938893903907228,
136 0.000000000000000003469446951953614,
137 0.000000000000000001734723475976807,
138 0.0000000000000000008673617379884035,
139 0.0000000000000000004336808689942018,
140 0.0000000000000000002168404344971009,
141 0.00000000000000000010842021724855044,
142];
143pub fn cordic<T: PrimitiveMath + One + Zero + FromF64 + PartialOrd + Copy>(alpha: T) -> (T, T) {
145 let k_n = T::from_f64(CORDIC_K_64);
146 let mut theta = T::ZERO;
147 let mut x = T::ONE;
148 let mut y = T::ZERO;
149 let mut p2i = T::ONE;
150 let mut idx = 0;
151 while idx < CORDIC_ITERS {
152 #[allow(clippy::indexing_slicing)]
153 let atan = T::from_f64(THETA_TABLE[idx]);
154 let xt = x;
155 if theta < alpha {
156 theta += atan;
157 x -= y * p2i;
158 y += xt * p2i;
159 } else {
160 theta -= atan;
161 x += y * p2i;
162 y -= xt * p2i;
163 }
164 p2i /= T::from_f64(2.);
165 idx += 1;
166 }
167 (x * k_n, y * k_n)
168}
169#[cfg(not(feature = "std"))]
170impl FloatExt for f64 {
171 type Type = f64;
172 type Size = u64;
173
174 fn trunc(self) -> f64 {
178 (self as u64) as f64
179 }
180
181 fn fract(self) -> f64 {
182 self - self.trunc()
183 }
184
185 fn abs(self) -> f64 {
188 f64::from_bits(self.to_bits() & 0x7FFF_FFFF_FFFF_FFFFu64)
189 }
190
191 fn round(self) -> f64 {
192 (self + 0.5 * self.signum()).trunc()
193 }
194
195 fn floor(self) -> f64 {
196 if self.is_sign_negative() {
197 return (self - 1.0).trunc();
198 }
199 self.trunc()
200 }
201
202 fn ceil(self) -> f64 {
203 if self.is_sign_positive() {
204 return (self + 1.0).trunc();
205 }
206 self.trunc()
207 }
208
209 fn signum(self) -> f64 {
210 if self.is_nan() {
211 return f64::NAN;
212 }
213 if self.is_sign_negative() {
214 return -1.0;
215 }
216 1.0
217 }
218
219 fn clamp(self, min: Self, max: Self) -> Self::Type {
220 if self < min {
221 return min;
222 } else if self > max {
223 return max;
224 }
225 self
226 }
227
228 fn exp(self) -> Self::Type {
231 if self.is_nan() || self.is_infinite() {
232 return self;
233 }
234 let mut out = 1.0;
235 let i = self;
236 let mut idx = 1;
237 let mut next = self;
238
239 while next.abs() != 0.0 {
240 out += next;
241 idx += 1;
242 next *= i / idx as Self::Type;
243 }
244
245 out
246 }
247
248 fn ln(self) -> Self::Type {
251 if !self.is_normal() {
252 return self;
253 }
254 let z = self;
255 if z == 0. {
256 return 1.;
257 } else if z < 0. {
258 return f64::NAN;
259 }
260 let iter = (z - 1.) / (z + 1.);
261 let mut out = 0.0;
262 let mut next = 2.0 * iter;
263 let mut idx = 1.0;
264 let mut base = iter;
265 while next != 0.0 {
266 out += next;
267 idx += 2.0;
268 base *= iter * iter;
269 next = 2.0 * base / idx;
270 }
271 out
272 }
273
274 fn log10(self) -> Self::Type {
275 self.ln() / core::f64::consts::LN_10
276 }
277
278 fn powf(self, a: Self::Type) -> Self::Type {
281 if !self.is_normal() {
282 return self;
283 }
284 let z = self;
285
286 (a * z.ln()).exp()
287 }
288
289 fn powi(self, val: i32) -> Self::Type {
291 if !self.is_normal() {
292 return self;
293 }
294 let mut out = self;
295 let i = self;
296 for _ in 0..val.abs() {
297 out *= i;
298 }
299 out
300 }
301
302 fn sqrt(self) -> Self::Type {
303 self.powf(0.5)
304 }
305
306 fn to_bits(self) -> Self::Size {
307 f64::to_bits(self)
308 }
309
310 fn exponent(self) -> u16 {
311 ((self.to_bits() >> 52) & 0x7FF) as u16
312 }
313
314 fn significand(self) -> Self::Size {
315 self.to_bits() & 0xF_FFFF_FFFF_FFFF
316 }
317
318 fn sin(self) -> Self::Type {
319 cordic(self).0
320 }
321 fn cos(self) -> Self::Type {
322 cordic(self).1
323 }
324
325 fn tan(self) -> Self::Type {
326 self.sin() / self.cos()
327 }
328
329 fn atan(self) -> Self::Type {
330 todo!()
331 }
332
333 fn atan2(self, _o: Self) -> Self::Type {
334 todo!()
335 }
336}
337
338#[cfg(feature = "std")]
339impl FloatExt for f64 {
340 type Type = f64;
341 type Size = u64;
342
343 fn trunc(self) -> Self::Type {
344 f64::trunc(self)
345 }
346
347 fn fract(self) -> Self::Type {
348 f64::fract(self)
349 }
350
351 fn abs(self) -> Self::Type {
352 f64::abs(self)
353 }
354
355 fn round(self) -> Self::Type {
356 f64::round(self)
357 }
358
359 fn floor(self) -> Self::Type {
360 f64::floor(self)
361 }
362
363 fn ceil(self) -> Self::Type {
364 f64::ceil(self)
365 }
366
367 fn signum(self) -> Self::Type {
368 f64::signum(self)
369 }
370
371 fn clamp(self, min: Self, max: Self) -> Self::Type {
372 f64::clamp(self, min, max)
373 }
374
375 fn exp(self) -> Self::Type {
376 f64::exp(self)
377 }
378
379 fn ln(self) -> Self::Type {
380 f64::ln(self)
381 }
382
383 fn log10(self) -> Self::Type {
384 f64::log10(self)
385 }
386
387 fn powi(self, val: i32) -> Self::Type {
388 f64::powi(self, val)
389 }
390
391 fn powf(self, val: Self::Type) -> Self::Type {
392 f64::powf(self, val)
393 }
394
395 fn sqrt(self) -> Self::Type {
396 f64::sqrt(self)
397 }
398
399 fn to_bits(self) -> Self::Size {
400 f64::to_bits(self)
401 }
402
403 fn exponent(self) -> u16 {
404 ((self.to_bits() >> 52) & 0x7FF) as u16
405 }
406
407 fn significand(self) -> Self::Size {
408 self.to_bits() & 0xF_FFFF_FFFF_FFFF
409 }
410
411 fn sin(self) -> Self::Type {
412 f64::sin(self)
413 }
414
415 fn cos(self) -> Self::Type {
416 f64::cos(self)
417 }
418
419 fn tan(self) -> Self::Type {
420 f64::tan(self)
421 }
422
423 fn atan(self) -> Self::Type {
424 f64::atan(self)
425 }
426
427 fn atan2(self, o: Self) -> Self::Type {
428 f64::atan2(self, o)
429 }
430}
431
432impl WrappingSub for f64 {
433 fn wrapping_sub(&self, rhs: Self) -> Self {
434 self - rhs
435 }
436}
437impl ToF64 for f64 {
438 fn to_f64(&self) -> f64 {
439 *self
440 }
441}
442impl FromF64 for f64 {
443 fn from_f64(value: f64) -> Self {
444 value
445 }
446}
447impl ToSigned for f64 {
448 type Output = f64;
449
450 fn to_signed(self) -> Self::Output {
451 self
452 }
453 fn negative_one() -> Self::Output {
454 -1.
455 }
456}
457
458impl PrimitiveMath for f64 {}
459impl FloatIsh for f64 {}
460
461#[cfg(test)]
462mod tests {
463 use crate::f64::{cordic, cordic_k};
464 use std::f64::consts::PI;
465
466 #[test]
467 pub fn test_ln() {
468 assert_eq_eps!(0.0, crate::f64::FloatExt::ln(1.0f64), 1e-16);
469 assert_eq_eps!(1.0, crate::f64::FloatExt::ln(core::f64::consts::E), 1e-15);
470 assert_eq_eps!(4.605170185988092, crate::f64::FloatExt::ln(100f64), 1e-13);
471 assert_eq_eps!(
472 11.090339630053647,
473 crate::f64::FloatExt::ln(u16::MAX as f64),
474 1e-11
475 );
476 }
477
478 #[test]
479 pub fn test_exp() {
480 assert_eq_eps!(1.0, crate::f64::FloatExt::exp(0.0f64), 1e-16);
481 assert_eq_eps!(
482 core::f64::consts::E,
483 crate::f64::FloatExt::exp(1.0f64),
484 1e-15
485 );
486 assert_eq_eps!(7.38905609893065, crate::f64::FloatExt::exp(2.0f64), 1e-14);
487 assert_eq_eps!(
488 15.154262241479262,
489 crate::f64::FloatExt::exp(core::f64::consts::E),
490 1e-15
491 );
492 }
493
494 #[test]
495 pub fn test_sqrt() {
496 assert_eq!(2., crate::f64::FloatExt::sqrt(4.0f64));
497 }
498
499 #[test]
500 #[ignore]
501 pub fn theta_table() {
502 println!("{}\n", cordic_k(80));
503 for i in 0..80 {
504 println!("{},", 1f64.atan2(2f64.powi(i)))
505 }
506 }
507 #[test]
508 pub fn test_cordic() {
509 for x in -90..90 {
510 let x = x as f64;
511 let angr = x * (PI / 180.);
512 let (cosx, sinx) = cordic(angr);
513 let dcos = cosx - angr.cos();
514 let dsin = sinx - angr.sin();
515 let dcosulps = dcos / f64::EPSILON;
516 let dsinulps = dsin / f64::EPSILON;
517 println!("{x:0.05} {sinx:0.16} {dsin:0.16} {dsinulps:0.1} {cosx:0.16} {dcos:0.16} {dcosulps:0.1}");
518 assert!(dcosulps.abs() < 5.0, "{x}");
519 assert!(dsinulps.abs() < 5.0, "{x}");
520 }
521 }
522}