1#![no_std]
8#![expect(non_snake_case, reason = "Proper mathematical names")]
9
10pub mod chebyshev;
11mod constants;
12mod implementation;
13
14pub mod neg {
15 use {
18 crate::{Approx, constants, implementation::neg, pos},
19 core::fmt,
20 sigma_types::{Finite, Negative},
21 };
22
23 #[non_exhaustive]
25 #[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
26 pub struct HugeArgument(pub Negative<Finite<f64>>);
27
28 impl fmt::Display for HugeArgument {
29 #[inline]
30 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31 let Self(ref arg) = *self;
32 write!(
33 f,
34 "Argument too large (negative): minimum is {}, but {arg} was supplied",
35 constants::NXMAX,
36 )
37 }
38 }
39
40 #[inline]
44 pub fn E1(
45 x: Negative<Finite<f64>>,
46 #[cfg(feature = "precision")] max_precision: usize,
47 ) -> Result<Approx, HugeArgument> {
48 neg::E1(
49 x,
50 #[cfg(feature = "precision")]
51 max_precision,
52 )
53 }
54
55 #[inline(always)]
59 pub fn Ei(
60 x: Negative<Finite<f64>>,
61 #[cfg(feature = "precision")] max_precision: usize,
62 ) -> Result<Approx, HugeArgument> {
63 #![expect(
64 clippy::arithmetic_side_effects,
65 reason = "property-based testing ensures this never happens"
66 )]
67
68 pos::E1(
69 -x,
70 #[cfg(feature = "precision")]
71 max_precision,
72 )
73 .map(|mut approx| {
74 approx.value = -approx.value;
75 approx
76 })
77 .map_err(|pos::HugeArgument(arg)| HugeArgument(-arg))
78 }
79}
80
81pub mod pos {
82 use {
85 crate::{Approx, constants, implementation::pos, neg},
86 core::fmt,
87 sigma_types::{Finite, Positive},
88 };
89
90 #[non_exhaustive]
92 #[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
93 pub struct HugeArgument(pub Positive<Finite<f64>>);
94
95 impl fmt::Display for HugeArgument {
96 #[inline]
97 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
98 let Self(ref arg) = *self;
99 write!(
100 f,
101 "Argument too large (positive): maximum is {}, but {arg} was supplied",
102 constants::XMAX,
103 )
104 }
105 }
106
107 #[inline]
111 pub fn E1(
112 x: Positive<Finite<f64>>,
113 #[cfg(feature = "precision")] max_precision: usize,
114 ) -> Result<Approx, HugeArgument> {
115 pos::E1(
116 x,
117 #[cfg(feature = "precision")]
118 max_precision,
119 )
120 }
121
122 #[inline(always)]
126 pub fn Ei(
127 x: Positive<Finite<f64>>,
128 #[cfg(feature = "precision")] max_precision: usize,
129 ) -> Result<Approx, HugeArgument> {
130 #![expect(
131 clippy::arithmetic_side_effects,
132 reason = "property-based testing ensures this never happens"
133 )]
134
135 neg::E1(
136 -x,
137 #[cfg(feature = "precision")]
138 max_precision,
139 )
140 .map(|mut approx| {
141 approx.value = -approx.value;
142 approx
143 })
144 .map_err(|neg::HugeArgument(arg)| HugeArgument(-arg))
145 }
146}
147
148#[cfg(test)]
149mod test;
150
151use {
152 core::fmt,
153 sigma_types::{Finite, Negative, NonZero, Positive},
154};
155
156#[cfg(feature = "error")]
157use sigma_types::NonNegative;
158
159#[expect(clippy::exhaustive_structs, reason = "Simple structure")]
169#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
170pub struct Approx {
171 #[cfg(feature = "error")]
173 pub error: NonNegative<Finite<f64>>,
174 pub value: Finite<f64>,
176}
177
178impl fmt::Display for Approx {
179 #[inline]
180 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
181 let Self {
182 #[cfg(feature = "error")]
183 ref error,
184 ref value,
185 } = *self;
186 #[cfg(feature = "error")]
187 {
188 write!(f, "{value} +/- {error}")
189 }
190 #[cfg(not(feature = "error"))]
191 {
192 write!(f, "{value}")
193 }
194 }
195}
196
197#[non_exhaustive]
199#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
200pub enum Error {
201 ArgumentTooNegative(Negative<Finite<f64>>),
203 ArgumentTooPositive(Positive<Finite<f64>>),
205}
206
207impl fmt::Display for Error {
208 #[inline]
209 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
210 match *self {
211 Self::ArgumentTooNegative(arg) => fmt::Display::fmt(&neg::HugeArgument(arg), f),
212 Self::ArgumentTooPositive(arg) => fmt::Display::fmt(&pos::HugeArgument(arg), f),
213 }
214 }
215}
216
217#[inline]
228pub fn E1(
229 x: NonZero<Finite<f64>>,
230 #[cfg(feature = "precision")] max_precision: usize,
231) -> Result<Approx, Error> {
232 implementation::E1(
233 x,
234 #[cfg(feature = "precision")]
235 max_precision,
236 )
237}
238
239#[inline(always)]
256pub fn Ei(
257 x: NonZero<Finite<f64>>,
258 #[cfg(feature = "precision")] max_precision: usize,
259) -> Result<Approx, Error> {
260 #![expect(
261 clippy::arithmetic_side_effects,
262 reason = "property-based testing ensures this never happens"
263 )]
264
265 E1(
266 -x,
267 #[cfg(feature = "precision")]
268 max_precision,
269 )
270 .map(|mut approx| {
271 approx.value = -approx.value;
272 approx
273 })
274}