Skip to main content

sim_lib_numbers_core/
limits.rs

1//! Canonical machine limits for fixed-width number domains.
2
3use sim_kernel::Symbol;
4
5use crate::domains;
6
7/// Machine limits exposed by a scalar number domain.
8#[derive(Clone, Copy, Debug, PartialEq)]
9pub struct MachineLimits {
10    /// Distance from one to the next representable value, when bounded.
11    pub epsilon: Option<f64>,
12    /// Smallest finite value representable by the domain.
13    pub minimum: Option<f64>,
14    /// Largest finite value representable by the domain.
15    pub maximum: Option<f64>,
16    /// Smallest positive normal value for floating domains.
17    pub minimum_positive: Option<f64>,
18}
19
20/// Returns canonical limits for a registered fixed-width domain.
21///
22/// Exact rationals are unbounded and have no machine epsilon, so all fields
23/// are `None`. Unknown and extensible domains likewise return `None` rather
24/// than borrowing another domain's constants.
25pub fn machine_limits(domain: &Symbol) -> Option<MachineLimits> {
26    if domain == &domains::f64() {
27        Some(MachineLimits {
28            epsilon: Some(f64::EPSILON),
29            minimum: Some(f64::MIN),
30            maximum: Some(f64::MAX),
31            minimum_positive: Some(f64::MIN_POSITIVE),
32        })
33    } else if domain == &domains::f32() {
34        Some(MachineLimits {
35            epsilon: Some(f32::EPSILON as f64),
36            minimum: Some(f32::MIN as f64),
37            maximum: Some(f32::MAX as f64),
38            minimum_positive: Some(f32::MIN_POSITIVE as f64),
39        })
40    } else if domain == &domains::i64() {
41        Some(MachineLimits {
42            epsilon: Some(1.0),
43            minimum: Some(i64::MIN as f64),
44            maximum: Some(i64::MAX as f64),
45            minimum_positive: Some(1.0),
46        })
47    } else if domain == &domains::rational() {
48        Some(MachineLimits {
49            epsilon: None,
50            minimum: None,
51            maximum: None,
52            minimum_positive: None,
53        })
54    } else {
55        None
56    }
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62    #[test]
63    fn fixed_and_exact_domain_limits_are_explicit() {
64        assert_eq!(
65            machine_limits(&domains::f32()).unwrap().epsilon,
66            Some(f32::EPSILON as f64)
67        );
68        assert_eq!(
69            machine_limits(&domains::i64()).unwrap().minimum_positive,
70            Some(1.0)
71        );
72        assert_eq!(machine_limits(&domains::rational()).unwrap().epsilon, None);
73    }
74}