#![no_std]
#![expect(non_snake_case, reason = "Proper mathematical names")]
pub mod chebyshev;
mod constants;
mod implementation;
pub mod neg {
use {
crate::{Approx, constants, implementation::neg, pos},
core::fmt,
sigma_types::{Finite, Negative},
};
#[non_exhaustive]
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
pub struct HugeArgument(pub Negative<Finite<f64>>);
impl fmt::Display for HugeArgument {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self(ref arg) = *self;
write!(
f,
"Argument too large (negative): minimum is {}, but {arg} was supplied",
constants::NXMAX,
)
}
}
#[inline]
pub fn E1(
x: Negative<Finite<f64>>,
#[cfg(feature = "precision")] max_precision: usize,
) -> Result<Approx, HugeArgument> {
neg::E1(
x,
#[cfg(feature = "precision")]
max_precision,
)
}
#[inline(always)]
pub fn Ei(
x: Negative<Finite<f64>>,
#[cfg(feature = "precision")] max_precision: usize,
) -> Result<Approx, HugeArgument> {
#![expect(
clippy::arithmetic_side_effects,
reason = "property-based testing ensures this never happens"
)]
pos::E1(
-x,
#[cfg(feature = "precision")]
max_precision,
)
.map(|mut approx| {
approx.value = -approx.value;
approx
})
.map_err(|pos::HugeArgument(arg)| HugeArgument(-arg))
}
}
pub mod pos {
use {
crate::{Approx, constants, implementation::pos, neg},
core::fmt,
sigma_types::{Finite, Positive},
};
#[non_exhaustive]
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
pub struct HugeArgument(pub Positive<Finite<f64>>);
impl fmt::Display for HugeArgument {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self(ref arg) = *self;
write!(
f,
"Argument too large (positive): maximum is {}, but {arg} was supplied",
constants::XMAX,
)
}
}
#[inline]
pub fn E1(
x: Positive<Finite<f64>>,
#[cfg(feature = "precision")] max_precision: usize,
) -> Result<Approx, HugeArgument> {
pos::E1(
x,
#[cfg(feature = "precision")]
max_precision,
)
}
#[inline(always)]
pub fn Ei(
x: Positive<Finite<f64>>,
#[cfg(feature = "precision")] max_precision: usize,
) -> Result<Approx, HugeArgument> {
#![expect(
clippy::arithmetic_side_effects,
reason = "property-based testing ensures this never happens"
)]
neg::E1(
-x,
#[cfg(feature = "precision")]
max_precision,
)
.map(|mut approx| {
approx.value = -approx.value;
approx
})
.map_err(|neg::HugeArgument(arg)| HugeArgument(-arg))
}
}
#[cfg(test)]
mod test;
use {
core::fmt,
sigma_types::{Finite, Negative, NonZero, Positive},
};
#[cfg(feature = "error")]
use sigma_types::NonNegative;
#[expect(clippy::exhaustive_structs, reason = "Simple structure")]
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
pub struct Approx {
#[cfg(feature = "error")]
pub error: NonNegative<Finite<f64>>,
pub value: Finite<f64>,
}
impl fmt::Display for Approx {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self {
#[cfg(feature = "error")]
ref error,
ref value,
} = *self;
#[cfg(feature = "error")]
{
write!(f, "{value} +/- {error}")
}
#[cfg(not(feature = "error"))]
{
write!(f, "{value}")
}
}
}
#[non_exhaustive]
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
pub enum Error {
ArgumentTooNegative(Negative<Finite<f64>>),
ArgumentTooPositive(Positive<Finite<f64>>),
}
impl fmt::Display for Error {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Self::ArgumentTooNegative(arg) => fmt::Display::fmt(&neg::HugeArgument(arg), f),
Self::ArgumentTooPositive(arg) => fmt::Display::fmt(&pos::HugeArgument(arg), f),
}
}
}
#[inline]
pub fn E1(
x: NonZero<Finite<f64>>,
#[cfg(feature = "precision")] max_precision: usize,
) -> Result<Approx, Error> {
implementation::E1(
x,
#[cfg(feature = "precision")]
max_precision,
)
}
#[inline(always)]
pub fn Ei(
x: NonZero<Finite<f64>>,
#[cfg(feature = "precision")] max_precision: usize,
) -> Result<Approx, Error> {
#![expect(
clippy::arithmetic_side_effects,
reason = "property-based testing ensures this never happens"
)]
E1(
-x,
#[cfg(feature = "precision")]
max_precision,
)
.map(|mut approx| {
approx.value = -approx.value;
approx
})
}