chj_rustbin/numbers.rs
1use std::cmp::Ordering;
2
3use num::{CheckedSub, Num};
4
5/// Get a function that reports whether two numbers are within maxdiff
6/// of each other (either direction).
7pub fn numbers_within<N>(maxdiff: N) -> impl Fn(N, N) -> bool
8where
9 N: CheckedSub + Num + Ord,
10{
11 move |a: N, b: N| -> bool {
12 if a > b {
13 a.checked_sub(&b).expect("should always work, am I wrong?")
14 < maxdiff
15 } else {
16 b.checked_sub(&a).expect("should always work, am I wrong?")
17 < maxdiff
18 }
19 }
20}
21
22/// std::cmp::max doesn't work on floating point
23pub fn max_f64(a: f64, b: f64) -> f64 {
24 if a < b {
25 b
26 } else {
27 a
28 }
29}
30
31/// Comparison between two values with only partial ordering
32/// (e.g. floating point numbers) that provides a fake full ordering
33/// by falling back to Ordering::Equal if non-comparable. Warning:
34/// this may not be what you want, but perhaps panic instead?
35pub fn forced_cmp<T: PartialOrd>(a: T, b: T) -> Ordering {
36 a.partial_cmp(&b).unwrap_or(Ordering::Equal)
37}
38
39/// An addition that ignores NaN numbers if possible (the result
40/// should only be NaN if both arguments are NaN). In other words, NaN
41/// is treated the same as 0, as long as at least one argument isn't
42/// NaN. (Warning: this might not be what you want.)
43pub fn nandropping_add(a: f64, b: f64) -> f64 {
44 if a.is_nan() {
45 b
46 } else if b.is_nan() {
47 a
48 } else {
49 a + b
50 }
51}