blob: a47883d81bb2def0915455bcb56b04eadafc70a4 [file] [log] [blame]
//! 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"));