| //! libm in pure Rust |
| //! |
| //! # Usage |
| //! |
| //! You can use this crate in two ways: |
| //! |
| //! - By directly using its free functions, e.g. `libm::powf`. |
| //! |
| //! - By importing the `F32Ext` and / or `F64Ext` extension traits to add methods like `powf` to the |
| //! `f32` and `f64` types. Then you'll be able to invoke math functions as methods, e.g. `x.sqrt()`. |
| |
| #![deny(warnings)] |
| #![no_std] |
| #![cfg_attr( |
| all(target_arch = "wasm32", not(feature = "stable")), |
| feature(core_intrinsics) |
| )] |
| |
| mod math; |
| |
| use core::{f32, f64}; |
| |
| pub use self::math::*; |
| |
| /// Approximate equality with 1 ULP of tolerance |
| #[doc(hidden)] |
| #[inline] |
| pub fn _eqf(a: f32, b: f32) -> Result<(), u32> { |
| if a.is_nan() && b.is_nan() { |
| Ok(()) |
| } else { |
| let err = (a.to_bits() as i32).wrapping_sub(b.to_bits() as i32).abs(); |
| |
| if err <= 1 { |
| Ok(()) |
| } else { |
| Err(err as u32) |
| } |
| } |
| } |
| |
| #[doc(hidden)] |
| #[inline] |
| pub fn _eq(a: f64, b: f64) -> Result<(), u64> { |
| if a.is_nan() && b.is_nan() { |
| Ok(()) |
| } else { |
| let err = (a.to_bits() as i64).wrapping_sub(b.to_bits() as i64).abs(); |
| |
| if err <= 1 { |
| Ok(()) |
| } else { |
| Err(err as u64) |
| } |
| } |
| } |
| |
| /// Math support for `f32` |
| /// |
| /// This trait is sealed and cannot be implemented outside of `libm`. |
| pub trait F32Ext: private::Sealed + Sized { |
| fn floor(self) -> Self; |
| |
| fn ceil(self) -> Self; |
| |
| fn round(self) -> Self; |
| |
| fn trunc(self) -> Self; |
| |
| fn fdim(self, rhs: Self) -> Self; |
| |
| fn fract(self) -> Self; |
| |
| fn abs(self) -> Self; |
| |
| // NOTE depends on unstable intrinsics::copysignf32 |
| // fn signum(self) -> Self; |
| |
| fn mul_add(self, a: Self, b: Self) -> Self; |
| |
| fn div_euc(self, rhs: Self) -> Self; |
| |
| fn mod_euc(self, rhs: Self) -> Self; |
| |
| // NOTE depends on unstable intrinsics::powif32 |
| // fn powi(self, n: i32) -> Self; |
| |
| fn powf(self, n: Self) -> Self; |
| |
| fn sqrt(self) -> Self; |
| |
| fn exp(self) -> Self; |
| |
| fn exp2(self) -> Self; |
| |
| fn ln(self) -> Self; |
| |
| fn log(self, base: Self) -> Self; |
| |
| fn log2(self) -> Self; |
| |
| fn log10(self) -> Self; |
| |
| fn cbrt(self) -> Self; |
| |
| fn hypot(self, other: Self) -> Self; |
| |
| fn sin(self) -> Self; |
| |
| fn cos(self) -> Self; |
| |
| fn tan(self) -> Self; |
| |
| fn asin(self) -> Self; |
| |
| fn acos(self) -> Self; |
| |
| fn atan(self) -> Self; |
| |
| fn atan2(self, other: Self) -> Self; |
| |
| fn sin_cos(self) -> (Self, Self); |
| |
| fn exp_m1(self) -> Self; |
| |
| fn ln_1p(self) -> Self; |
| |
| fn sinh(self) -> Self; |
| |
| fn cosh(self) -> Self; |
| |
| fn tanh(self) -> Self; |
| |
| fn asinh(self) -> Self; |
| |
| fn acosh(self) -> Self; |
| |
| fn atanh(self) -> Self; |
| |
| fn min(self, other: Self) -> Self; |
| |
| fn max(self, other: Self) -> Self; |
| } |
| |
| impl F32Ext for f32 { |
| #[inline] |
| fn floor(self) -> Self { |
| floorf(self) |
| } |
| |
| #[inline] |
| fn ceil(self) -> Self { |
| ceilf(self) |
| } |
| |
| #[inline] |
| fn round(self) -> Self { |
| roundf(self) |
| } |
| |
| #[inline] |
| fn trunc(self) -> Self { |
| truncf(self) |
| } |
| |
| #[inline] |
| fn fdim(self, rhs: Self) -> Self { |
| fdimf(self, rhs) |
| } |
| |
| #[inline] |
| fn fract(self) -> Self { |
| self - self.trunc() |
| } |
| |
| #[inline] |
| fn abs(self) -> Self { |
| fabsf(self) |
| } |
| |
| #[inline] |
| fn mul_add(self, a: Self, b: Self) -> Self { |
| fmaf(self, a, b) |
| } |
| |
| #[inline] |
| fn div_euc(self, rhs: Self) -> Self { |
| let q = (self / rhs).trunc(); |
| if self % rhs < 0.0 { |
| return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }; |
| } |
| q |
| } |
| |
| #[inline] |
| fn mod_euc(self, rhs: f32) -> f32 { |
| let r = self % rhs; |
| if r < 0.0 { |
| r + rhs.abs() |
| } else { |
| r |
| } |
| } |
| |
| #[inline] |
| fn powf(self, n: Self) -> Self { |
| powf(self, n) |
| } |
| |
| #[inline] |
| fn sqrt(self) -> Self { |
| sqrtf(self) |
| } |
| |
| #[inline] |
| fn exp(self) -> Self { |
| expf(self) |
| } |
| |
| #[inline] |
| fn exp2(self) -> Self { |
| exp2f(self) |
| } |
| |
| #[inline] |
| fn ln(self) -> Self { |
| logf(self) |
| } |
| |
| #[inline] |
| fn log(self, base: Self) -> Self { |
| self.ln() / base.ln() |
| } |
| |
| #[inline] |
| fn log2(self) -> Self { |
| log2f(self) |
| } |
| |
| #[inline] |
| fn log10(self) -> Self { |
| log10f(self) |
| } |
| |
| #[inline] |
| fn cbrt(self) -> Self { |
| cbrtf(self) |
| } |
| |
| #[inline] |
| fn hypot(self, other: Self) -> Self { |
| hypotf(self, other) |
| } |
| |
| #[inline] |
| fn sin(self) -> Self { |
| sinf(self) |
| } |
| |
| #[inline] |
| fn cos(self) -> Self { |
| cosf(self) |
| } |
| |
| #[inline] |
| fn tan(self) -> Self { |
| tanf(self) |
| } |
| |
| #[inline] |
| fn asin(self) -> Self { |
| asinf(self) |
| } |
| |
| #[inline] |
| fn acos(self) -> Self { |
| acosf(self) |
| } |
| |
| #[inline] |
| fn atan(self) -> Self { |
| atanf(self) |
| } |
| |
| #[inline] |
| fn atan2(self, other: Self) -> Self { |
| atan2f(self, other) |
| } |
| |
| #[inline] |
| fn sin_cos(self) -> (Self, Self) { |
| sincosf(self) |
| } |
| |
| #[inline] |
| fn exp_m1(self) -> Self { |
| expm1f(self) |
| } |
| |
| #[inline] |
| fn ln_1p(self) -> Self { |
| log1pf(self) |
| } |
| |
| #[inline] |
| fn sinh(self) -> Self { |
| sinhf(self) |
| } |
| |
| #[inline] |
| fn cosh(self) -> Self { |
| coshf(self) |
| } |
| |
| #[inline] |
| fn tanh(self) -> Self { |
| tanhf(self) |
| } |
| |
| #[inline] |
| fn asinh(self) -> Self { |
| asinhf(self) |
| } |
| |
| #[inline] |
| fn acosh(self) -> Self { |
| acoshf(self) |
| } |
| |
| #[inline] |
| fn atanh(self) -> Self { |
| atanhf(self) |
| } |
| |
| #[inline] |
| fn min(self, other: Self) -> Self { |
| fminf(self, other) |
| } |
| |
| #[inline] |
| fn max(self, other: Self) -> Self { |
| fmaxf(self, other) |
| } |
| } |
| |
| /// Math support for `f64` |
| /// |
| /// This trait is sealed and cannot be implemented outside of `libm`. |
| pub trait F64Ext: private::Sealed + Sized { |
| fn floor(self) -> Self; |
| |
| fn ceil(self) -> Self; |
| |
| fn round(self) -> Self; |
| |
| fn trunc(self) -> Self; |
| |
| fn fdim(self, rhs: Self) -> Self; |
| |
| fn fract(self) -> Self; |
| |
| fn abs(self) -> Self; |
| |
| // NOTE depends on unstable intrinsics::copysignf64 |
| // fn signum(self) -> Self; |
| |
| fn mul_add(self, a: Self, b: Self) -> Self; |
| |
| fn div_euc(self, rhs: Self) -> Self; |
| |
| fn mod_euc(self, rhs: Self) -> Self; |
| |
| // NOTE depends on unstable intrinsics::powif64 |
| // fn powi(self, n: i32) -> Self; |
| |
| fn powf(self, n: Self) -> Self; |
| |
| fn sqrt(self) -> Self; |
| |
| fn exp(self) -> Self; |
| |
| fn exp2(self) -> Self; |
| |
| fn ln(self) -> Self; |
| |
| fn log(self, base: Self) -> Self; |
| |
| fn log2(self) -> Self; |
| |
| fn log10(self) -> Self; |
| |
| fn cbrt(self) -> Self; |
| |
| fn hypot(self, other: Self) -> Self; |
| |
| fn sin(self) -> Self; |
| |
| fn cos(self) -> Self; |
| |
| fn tan(self) -> Self; |
| |
| fn asin(self) -> Self; |
| |
| fn acos(self) -> Self; |
| |
| fn atan(self) -> Self; |
| |
| fn atan2(self, other: Self) -> Self; |
| |
| fn sin_cos(self) -> (Self, Self); |
| |
| fn exp_m1(self) -> Self; |
| |
| fn ln_1p(self) -> Self; |
| |
| fn sinh(self) -> Self; |
| |
| fn cosh(self) -> Self; |
| |
| fn tanh(self) -> Self; |
| |
| fn asinh(self) -> Self; |
| |
| fn acosh(self) -> Self; |
| |
| fn atanh(self) -> Self; |
| |
| fn min(self, other: Self) -> Self; |
| |
| fn max(self, other: Self) -> Self; |
| } |
| |
| impl F64Ext for f64 { |
| #[inline] |
| fn floor(self) -> Self { |
| floor(self) |
| } |
| |
| #[inline] |
| fn ceil(self) -> Self { |
| ceil(self) |
| } |
| |
| #[inline] |
| fn round(self) -> Self { |
| round(self) |
| } |
| |
| #[inline] |
| fn trunc(self) -> Self { |
| trunc(self) |
| } |
| |
| #[inline] |
| fn fdim(self, rhs: Self) -> Self { |
| fdim(self, rhs) |
| } |
| |
| #[inline] |
| fn fract(self) -> Self { |
| self - self.trunc() |
| } |
| |
| #[inline] |
| fn abs(self) -> Self { |
| fabs(self) |
| } |
| |
| #[inline] |
| fn mul_add(self, a: Self, b: Self) -> Self { |
| fma(self, a, b) |
| } |
| |
| #[inline] |
| fn div_euc(self, rhs: Self) -> Self { |
| let q = (self / rhs).trunc(); |
| if self % rhs < 0.0 { |
| return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }; |
| } |
| q |
| } |
| |
| #[inline] |
| fn mod_euc(self, rhs: f64) -> f64 { |
| let r = self % rhs; |
| if r < 0.0 { |
| r + rhs.abs() |
| } else { |
| r |
| } |
| } |
| |
| #[inline] |
| fn powf(self, n: Self) -> Self { |
| pow(self, n) |
| } |
| |
| #[inline] |
| fn sqrt(self) -> Self { |
| sqrt(self) |
| } |
| |
| #[inline] |
| fn exp(self) -> Self { |
| exp(self) |
| } |
| |
| #[inline] |
| fn exp2(self) -> Self { |
| exp2(self) |
| } |
| |
| #[inline] |
| fn ln(self) -> Self { |
| log(self) |
| } |
| |
| #[inline] |
| fn log(self, base: Self) -> Self { |
| self.ln() / base.ln() |
| } |
| |
| #[inline] |
| fn log2(self) -> Self { |
| log2(self) |
| } |
| |
| #[inline] |
| fn log10(self) -> Self { |
| log10(self) |
| } |
| |
| #[inline] |
| fn cbrt(self) -> Self { |
| cbrt(self) |
| } |
| |
| #[inline] |
| fn hypot(self, other: Self) -> Self { |
| hypot(self, other) |
| } |
| |
| #[inline] |
| fn sin(self) -> Self { |
| sin(self) |
| } |
| |
| #[inline] |
| fn cos(self) -> Self { |
| cos(self) |
| } |
| |
| #[inline] |
| fn tan(self) -> Self { |
| tan(self) |
| } |
| |
| #[inline] |
| fn asin(self) -> Self { |
| asin(self) |
| } |
| |
| #[inline] |
| fn acos(self) -> Self { |
| acos(self) |
| } |
| |
| #[inline] |
| fn atan(self) -> Self { |
| atan(self) |
| } |
| |
| #[inline] |
| fn atan2(self, other: Self) -> Self { |
| atan2(self, other) |
| } |
| |
| #[inline] |
| fn sin_cos(self) -> (Self, Self) { |
| sincos(self) |
| } |
| |
| #[inline] |
| fn exp_m1(self) -> Self { |
| expm1(self) |
| } |
| |
| #[inline] |
| fn ln_1p(self) -> Self { |
| log1p(self) |
| } |
| |
| #[inline] |
| fn sinh(self) -> Self { |
| sinh(self) |
| } |
| |
| #[inline] |
| fn cosh(self) -> Self { |
| cosh(self) |
| } |
| |
| #[inline] |
| fn tanh(self) -> Self { |
| tanh(self) |
| } |
| |
| #[inline] |
| fn asinh(self) -> Self { |
| asinh(self) |
| } |
| |
| #[inline] |
| fn acosh(self) -> Self { |
| acosh(self) |
| } |
| |
| #[inline] |
| fn atanh(self) -> Self { |
| atanh(self) |
| } |
| |
| #[inline] |
| fn min(self, other: Self) -> Self { |
| fmin(self, other) |
| } |
| |
| #[inline] |
| fn max(self, other: Self) -> Self { |
| fmax(self, other) |
| } |
| } |
| |
| mod private { |
| pub trait Sealed {} |
| |
| impl Sealed for f32 {} |
| impl Sealed for f64 {} |
| } |
| |
| #[cfg(all(test, feature = "musl-reference-tests"))] |
| include!(concat!(env!("OUT_DIR"), "/musl-tests.rs")); |