1use 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
16pub 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 fn from_f64(value: f64) -> Self;
38
39 fn to_f64(self) -> f64;
41
42 fn sqrt_precise(self) -> Self;
44
45 fn powf_precise(self, exp: Self) -> Self;
47
48 fn sin_precise(self) -> Self;
50 fn cos_precise(self) -> Self;
52 fn tan_precise(self) -> Self;
54
55 fn sinh_precise(self) -> Self;
57 fn cosh_precise(self) -> Self;
59 fn tanh_precise(self) -> Self;
61
62 fn ln_precise(self) -> Self;
64
65 fn exp_precise(self) -> Self;
67
68 fn abs_precise(self) -> Self;
70
71 fn epsilon() -> Self;
73
74 fn default_tolerance() -> Self;
76
77 fn orbital_tolerance() -> Self;
79}
80
81impl 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#[cfg(feature = "high-precision")]
166#[derive(Clone, Debug)]
167pub struct HighPrecisionFloat {
168 value: rug::Float,
170 precision: u32,
172}
173
174#[cfg(feature = "high-precision")]
175impl HighPrecisionFloat {
176 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 pub fn standard(value: f64) -> Self {
186 Self::with_precision(value, 128)
187 }
188
189 pub fn high(value: f64) -> Self {
191 Self::with_precision(value, 256)
192 }
193
194 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
221pub type StandardFloat = f64;
226
227#[cfg(feature = "high-precision")]
229pub type ExtendedFloat = HighPrecisionFloat;
230
231#[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}