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}