amari_core/
precision.rs

1//! High-precision arithmetic traits for scientific computing
2//!
3//! This module provides a unified interface for different precision levels:
4//! - Standard f64 for general use
5//! - Arbitrary precision using rug::Float for critical calculations
6//! - Configurable precision based on application requirements
7
8use num_traits::{Float as NumFloat, FloatConst, FromPrimitive, One, ToPrimitive, Zero};
9
10#[cfg(feature = "std")]
11use std::fmt::{Debug, Display};
12
13#[cfg(not(feature = "std"))]
14use core::fmt::{Debug, Display};
15
16/// Unified trait for floating-point arithmetic in scientific computing
17///
18/// This trait abstracts over different precision levels to allow
19/// mathematical calculations with appropriate numerical accuracy.
20pub trait PrecisionFloat:
21    Clone
22    + Debug
23    + Display
24    + PartialEq
25    + PartialOrd
26    + NumFloat
27    + FloatConst
28    + FromPrimitive
29    + ToPrimitive
30    + Zero
31    + One
32    + Send
33    + Sync
34    + 'static
35{
36    /// Create from f64 value
37    fn from_f64(value: f64) -> Self;
38
39    /// Convert to f64 (may lose precision)
40    fn to_f64(self) -> f64;
41
42    /// Square root with high precision
43    fn sqrt_precise(self) -> Self;
44
45    /// Power function with high precision
46    fn powf_precise(self, exp: Self) -> Self;
47
48    /// Trigonometric functions with high precision
49    fn sin_precise(self) -> Self;
50    /// Cosine function with high precision
51    fn cos_precise(self) -> Self;
52    /// Tangent function with high precision
53    fn tan_precise(self) -> Self;
54
55    /// Hyperbolic functions with high precision
56    fn sinh_precise(self) -> Self;
57    /// Hyperbolic cosine with high precision
58    fn cosh_precise(self) -> Self;
59    /// Hyperbolic tangent with high precision
60    fn tanh_precise(self) -> Self;
61
62    /// Natural logarithm with high precision
63    fn ln_precise(self) -> Self;
64
65    /// Exponential function with high precision
66    fn exp_precise(self) -> Self;
67
68    /// Absolute value
69    fn abs_precise(self) -> Self;
70
71    /// Machine epsilon for this precision level
72    fn epsilon() -> Self;
73
74    /// Recommended tolerance for numerical calculations
75    fn default_tolerance() -> Self;
76
77    /// Specialized tolerance for orbital mechanics calculations
78    fn orbital_tolerance() -> Self;
79}
80
81/// Standard f64 implementation for general use
82impl PrecisionFloat for f64 {
83    #[inline]
84    fn from_f64(value: f64) -> Self {
85        value
86    }
87
88    #[inline]
89    fn to_f64(self) -> f64 {
90        self
91    }
92
93    #[inline]
94    fn sqrt_precise(self) -> Self {
95        self.sqrt()
96    }
97
98    #[inline]
99    fn powf_precise(self, exp: Self) -> Self {
100        self.powf(exp)
101    }
102
103    #[inline]
104    fn sin_precise(self) -> Self {
105        self.sin()
106    }
107
108    #[inline]
109    fn cos_precise(self) -> Self {
110        self.cos()
111    }
112
113    #[inline]
114    fn tan_precise(self) -> Self {
115        self.tan()
116    }
117
118    #[inline]
119    fn sinh_precise(self) -> Self {
120        self.sinh()
121    }
122
123    #[inline]
124    fn cosh_precise(self) -> Self {
125        self.cosh()
126    }
127
128    #[inline]
129    fn tanh_precise(self) -> Self {
130        self.tanh()
131    }
132
133    #[inline]
134    fn ln_precise(self) -> Self {
135        self.ln()
136    }
137
138    #[inline]
139    fn exp_precise(self) -> Self {
140        self.exp()
141    }
142
143    #[inline]
144    fn abs_precise(self) -> Self {
145        self.abs()
146    }
147
148    #[inline]
149    fn epsilon() -> Self {
150        f64::EPSILON
151    }
152
153    #[inline]
154    fn default_tolerance() -> Self {
155        1e-12
156    }
157
158    #[inline]
159    fn orbital_tolerance() -> Self {
160        1e-15
161    }
162}
163
164/// High-precision wrapper around rug::Float for critical calculations
165#[cfg(feature = "high-precision")]
166#[derive(Clone, Debug)]
167pub struct HighPrecisionFloat {
168    /// The arbitrary precision floating point value
169    value: rug::Float,
170    /// Precision in bits
171    precision: u32,
172}
173
174#[cfg(feature = "high-precision")]
175impl HighPrecisionFloat {
176    /// Create with specified precision (bits)
177    pub fn with_precision(value: f64, precision: u32) -> Self {
178        Self {
179            value: rug::Float::with_val(precision, value),
180            precision,
181        }
182    }
183
184    /// Create with standard precision (128 bits)
185    pub fn standard(value: f64) -> Self {
186        Self::with_precision(value, 128)
187    }
188
189    /// Create with high precision (256 bits) for critical calculations
190    pub fn high(value: f64) -> Self {
191        Self::with_precision(value, 256)
192    }
193
194    /// Get the precision in bits
195    pub fn precision(&self) -> u32 {
196        self.precision
197    }
198}
199
200#[cfg(feature = "high-precision")]
201impl PartialEq for HighPrecisionFloat {
202    fn eq(&self, other: &Self) -> bool {
203        self.value == other.value
204    }
205}
206
207#[cfg(feature = "high-precision")]
208impl PartialOrd for HighPrecisionFloat {
209    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
210        self.value.partial_cmp(&other.value)
211    }
212}
213
214#[cfg(feature = "high-precision")]
215impl Display for HighPrecisionFloat {
216    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
217        write!(f, "{}", self.value)
218    }
219}
220
221// TODO: Implement NumFloat and other required traits for HighPrecisionFloat
222// This would require substantial implementation for full compatibility
223
224/// Type alias for standard precision calculations
225pub type StandardFloat = f64;
226
227/// Type alias for high precision calculations when available
228#[cfg(feature = "high-precision")]
229pub type ExtendedFloat = HighPrecisionFloat;
230
231/// Type alias using standard precision when high-precision unavailable
232#[cfg(not(feature = "high-precision"))]
233pub type ExtendedFloat = f64;
234
235#[cfg(test)]
236mod tests {
237    use super::*;
238
239    #[test]
240    fn test_standard_float_precision() {
241        let x = 2.0_f64;
242        assert!((x.sqrt_precise() - f64::sqrt(2.0)).abs() < f64::EPSILON);
243        assert!((x.powf_precise(3.0) - 8.0).abs() < f64::EPSILON);
244    }
245
246    #[test]
247    fn test_default_tolerance() {
248        assert!(f64::default_tolerance() < f64::EPSILON.sqrt());
249        assert!(f64::default_tolerance() > 0.0);
250    }
251
252    #[cfg(feature = "high-precision")]
253    #[test]
254    fn test_high_precision_creation() {
255        let hp = HighPrecisionFloat::standard(std::f64::consts::PI);
256        assert_eq!(hp.precision(), 128);
257
258        let sp = HighPrecisionFloat::high(std::f64::consts::E);
259        assert_eq!(sp.precision(), 256);
260    }
261}