1use super::{Error, Result};
2use std::sync::Arc;
3
4pub fn cmp(x: f64, y: f64) -> i32 {
5 match (x.is_nan(), y.is_nan()) {
6 (false, false) => match (x == 0.0, y == 0.0) {
7 (true, true) => (x.signum() - y.signum()) as i32,
8 _ => x.partial_cmp(&y).unwrap() as i32,
9 },
10 (x, y) => (x as i32) - (y as i32),
11 }
12 .signum()
13}
14
15pub fn cmp_option(x: Option<f64>, y: Option<f64>) -> i32 {
16 match (x, y) {
17 (Some(x), Some(y)) => cmp(x, y),
18 _ => x.partial_cmp(&y).unwrap() as i32,
19 }
20}
21
22pub fn div(x: f64, y: f64) -> Result<f64> {
23 if y == 0.0 {
24 return Err(Error::new());
25 }
26 Ok(x / y)
27}
28
29pub fn max(x: f64, y: f64) -> f64 {
30 if x.is_nan() || y.is_nan() {
31 return f64::NAN;
32 }
33 x.max(y)
34}
35
36pub fn min(x: f64, y: f64) -> f64 {
37 if x.is_nan() || y.is_nan() {
38 return f64::NAN;
39 }
40 x.min(y)
41}
42
43pub fn near(x: f64, y: f64, rel_tol: Option<f64>, abs_tol: Option<f64>) -> bool {
44 let rel_tol = rel_tol.unwrap_or(1e-9);
45 let abs_tol = abs_tol.unwrap_or(0.0);
46 let margin = (x.abs().max(y.abs()) * rel_tol).max(abs_tol);
47 (x - y).abs() < margin
48}
49
50pub fn rem(x: f64, y: f64) -> Result<f64> {
51 if y == 0.0 {
52 return Err(Error::new());
53 }
54 Ok(x % y)
55}
56
57pub fn sign(x: f64) -> f64 {
58 match () {
59 _ if x == 0.0 => x,
60 _ => x.signum(),
61 }
62}
63
64pub fn to_int(x: f64) -> Result<i32> {
65 match () {
66 _ if x > (i32::MIN as f64) - 1.0 && x < (i32::MAX as f64) + 1.0 => Ok(x as i32),
67 _ => Err(Error::new()),
68 }
69}
70
71const MANTISSA_MAX: f64 = (1i64 << 53) as f64;
72
73pub fn to_int64(x: f64) -> Result<i64> {
74 match () {
75 _ if x > -MANTISSA_MAX && x < MANTISSA_MAX => Ok(x as i64),
76 _ => Err(Error::new()),
77 }
78}
79
80pub fn to_string(x: f64) -> Arc<String> {
81 match () {
82 _ if x == f64::INFINITY => "Infinity".to_string(),
84 _ if x == f64::NEG_INFINITY => "-Infinity".to_string(),
85 _ if x.is_nan() => "NaN".to_string(),
87 _ => match () {
88 _ if x == 0.0 || (0.001..10_000_000.0).contains(&x.abs()) => {
89 let mut text = x.to_string();
90 if !text.contains('.') {
91 text.push_str(".0");
92 }
93 text
94 }
95 _ => {
96 let mut text = format!("{x:e}");
97 if x.abs() > 1.0 {
98 let index = text.find('e').unwrap();
99 let replacement = match () {
100 _ if text.contains('.') => "e+",
101 _ => ".0e+",
102 };
103 text.replace_range(index..index + 1, replacement);
104 }
105 text
106 }
107 },
108 }
109 .into()
110}