mirror of
https://github.com/rust-lang/rust.git
synced 2025-11-17 13:35:51 +00:00
652 lines
11 KiB
Rust
652 lines
11 KiB
Rust
//! Port of MUSL's libm to 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]
|
|
|
|
mod math;
|
|
|
|
#[cfg(todo)]
|
|
use core::{f32, f64};
|
|
|
|
pub use math::*;
|
|
|
|
/// Approximate equality with 1 ULP of tolerance
|
|
#[doc(hidden)]
|
|
pub fn _eqf(a: u32, b: u32) -> bool {
|
|
(a as i32).wrapping_sub(b as i32).abs() <= 1
|
|
}
|
|
|
|
#[doc(hidden)]
|
|
pub fn _eq(a: u64, b: u64) -> bool {
|
|
(a as i64).wrapping_sub(b as i64).abs() <= 1
|
|
}
|
|
|
|
/// Math support for `f32`
|
|
///
|
|
/// This trait is sealed and cannot be implemented outside of `libm`.
|
|
pub trait F32Ext: private::Sealed {
|
|
fn floor(self) -> Self;
|
|
|
|
fn ceil(self) -> Self;
|
|
|
|
fn round(self) -> Self;
|
|
|
|
fn trunc(self) -> Self;
|
|
|
|
fn fdim(self, rhs: Self) -> Self;
|
|
|
|
#[cfg(todo)]
|
|
fn fract(self) -> Self;
|
|
|
|
fn abs(self) -> Self;
|
|
|
|
#[cfg(todo)]
|
|
fn signum(self) -> Self;
|
|
|
|
#[cfg(todo)]
|
|
fn mul_add(self, a: Self, b: Self) -> Self;
|
|
|
|
#[cfg(todo)]
|
|
fn div_euc(self, rhs: Self) -> Self;
|
|
|
|
#[cfg(todo)]
|
|
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;
|
|
|
|
#[cfg(todo)]
|
|
fn atan2(self, other: Self) -> Self;
|
|
|
|
#[cfg(todo)]
|
|
#[inline]
|
|
fn sin_cos(self) -> (Self, Self) {
|
|
(self.sin(), self.cos())
|
|
}
|
|
|
|
fn exp_m1(self) -> Self;
|
|
|
|
fn ln_1p(self) -> Self;
|
|
|
|
#[cfg(todo)]
|
|
fn sinh(self) -> Self;
|
|
|
|
#[cfg(todo)]
|
|
fn cosh(self) -> Self;
|
|
|
|
#[cfg(todo)]
|
|
fn tanh(self) -> Self;
|
|
|
|
#[cfg(todo)]
|
|
fn asinh(self) -> Self;
|
|
|
|
#[cfg(todo)]
|
|
fn acosh(self) -> Self;
|
|
|
|
#[cfg(todo)]
|
|
fn atanh(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)
|
|
}
|
|
|
|
#[cfg(todo)]
|
|
#[inline]
|
|
fn fract(self) -> Self {
|
|
self - self.trunc()
|
|
}
|
|
|
|
#[inline]
|
|
fn abs(self) -> Self {
|
|
fabsf(self)
|
|
}
|
|
|
|
#[cfg(todo)]
|
|
#[inline]
|
|
fn mul_add(self, a: Self, b: Self) -> Self {
|
|
fmaf(self, a, b)
|
|
}
|
|
|
|
#[cfg(todo)]
|
|
#[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
|
|
}
|
|
|
|
#[cfg(todo)]
|
|
#[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)
|
|
}
|
|
|
|
#[cfg(todo)]
|
|
#[inline]
|
|
fn atan2(self, other: Self) -> Self {
|
|
atan2f(self, other)
|
|
}
|
|
|
|
#[inline]
|
|
fn exp_m1(self) -> Self {
|
|
expm1f(self)
|
|
}
|
|
|
|
#[inline]
|
|
fn ln_1p(self) -> Self {
|
|
log1pf(self)
|
|
}
|
|
|
|
#[cfg(todo)]
|
|
#[inline]
|
|
fn sinh(self) -> Self {
|
|
sinhf(self)
|
|
}
|
|
|
|
#[cfg(todo)]
|
|
#[inline]
|
|
fn cosh(self) -> Self {
|
|
coshf(self)
|
|
}
|
|
|
|
#[cfg(todo)]
|
|
#[inline]
|
|
fn tanh(self) -> Self {
|
|
tanhf(self)
|
|
}
|
|
|
|
#[cfg(todo)]
|
|
#[inline]
|
|
fn asinh(self) -> Self {
|
|
if self == f32::NEG_INFINITY {
|
|
f32::NEG_INFINITY
|
|
} else {
|
|
(self + ((self * self) + 1.0).sqrt()).ln()
|
|
}
|
|
}
|
|
|
|
#[cfg(todo)]
|
|
#[inline]
|
|
fn acosh(self) -> Self {
|
|
match self {
|
|
x if x < 1.0 => f32::NAN,
|
|
x => (x + ((x * x) - 1.0).sqrt()).ln(),
|
|
}
|
|
}
|
|
|
|
#[cfg(todo)]
|
|
#[inline]
|
|
fn atanh(self) -> Self {
|
|
0.5 * ((2.0 * self) / (1.0 - self)).ln_1p()
|
|
}
|
|
}
|
|
|
|
/// Math support for `f64`
|
|
///
|
|
/// This trait is sealed and cannot be implemented outside of `libm`.
|
|
pub trait F64Ext: private::Sealed {
|
|
fn floor(self) -> Self;
|
|
|
|
fn ceil(self) -> Self;
|
|
|
|
fn round(self) -> Self;
|
|
|
|
fn trunc(self) -> Self;
|
|
|
|
fn fdim(self, rhs: Self) -> Self;
|
|
|
|
#[cfg(todo)]
|
|
fn fract(self) -> Self;
|
|
|
|
fn abs(self) -> Self;
|
|
|
|
#[cfg(todo)]
|
|
fn signum(self) -> Self;
|
|
|
|
fn mul_add(self, a: Self, b: Self) -> Self;
|
|
|
|
#[cfg(todo)]
|
|
fn div_euc(self, rhs: Self) -> Self;
|
|
|
|
#[cfg(todo)]
|
|
fn mod_euc(self, rhs: Self) -> Self;
|
|
|
|
// NOTE depends on unstable intrinsics::powif64
|
|
// fn powi(self, n: i32) -> Self;
|
|
|
|
#[cfg(todo)]
|
|
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;
|
|
|
|
#[cfg(todo)]
|
|
fn sin(self) -> Self;
|
|
|
|
#[cfg(todo)]
|
|
fn cos(self) -> Self;
|
|
|
|
#[cfg(todo)]
|
|
fn tan(self) -> Self;
|
|
|
|
#[cfg(todo)]
|
|
fn asin(self) -> Self;
|
|
|
|
fn acos(self) -> Self;
|
|
|
|
#[cfg(todo)]
|
|
fn atan(self) -> Self;
|
|
|
|
#[cfg(todo)]
|
|
fn atan2(self, other: Self) -> Self;
|
|
|
|
#[cfg(todo)]
|
|
#[inline]
|
|
fn sin_cos(self) -> (Self, Self) {
|
|
(self.sin(), self.cos())
|
|
}
|
|
|
|
fn exp_m1(self) -> Self;
|
|
|
|
fn ln_1p(self) -> Self;
|
|
|
|
#[cfg(todo)]
|
|
fn sinh(self) -> Self;
|
|
|
|
#[cfg(todo)]
|
|
fn cosh(self) -> Self;
|
|
|
|
#[cfg(todo)]
|
|
fn tanh(self) -> Self;
|
|
|
|
#[cfg(todo)]
|
|
fn asinh(self) -> Self;
|
|
|
|
#[cfg(todo)]
|
|
fn acosh(self) -> Self;
|
|
|
|
#[cfg(todo)]
|
|
fn atanh(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)
|
|
}
|
|
#[cfg(todo)]
|
|
#[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)
|
|
}
|
|
|
|
#[cfg(todo)]
|
|
#[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
|
|
}
|
|
|
|
#[cfg(todo)]
|
|
#[inline]
|
|
fn mod_euc(self, rhs: f32) -> f32 {
|
|
let r = self % rhs;
|
|
if r < 0.0 {
|
|
r + rhs.abs()
|
|
} else {
|
|
r
|
|
}
|
|
}
|
|
|
|
#[cfg(todo)]
|
|
#[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)
|
|
}
|
|
|
|
#[cfg(todo)]
|
|
#[inline]
|
|
fn sin(self) -> Self {
|
|
sin(self)
|
|
}
|
|
|
|
#[cfg(todo)]
|
|
#[inline]
|
|
fn cos(self) -> Self {
|
|
cos(self)
|
|
}
|
|
|
|
#[cfg(todo)]
|
|
#[inline]
|
|
fn tan(self) -> Self {
|
|
tan(self)
|
|
}
|
|
|
|
#[cfg(todo)]
|
|
#[inline]
|
|
fn asin(self) -> Self {
|
|
asin(self)
|
|
}
|
|
|
|
#[inline]
|
|
fn acos(self) -> Self {
|
|
acos(self)
|
|
}
|
|
|
|
#[cfg(todo)]
|
|
#[inline]
|
|
fn atan(self) -> Self {
|
|
atan(self)
|
|
}
|
|
|
|
#[cfg(todo)]
|
|
#[inline]
|
|
fn atan2(self, other: Self) -> Self {
|
|
atan2(self, other)
|
|
}
|
|
|
|
#[inline]
|
|
fn exp_m1(self) -> Self {
|
|
expm1(self)
|
|
}
|
|
|
|
#[inline]
|
|
fn ln_1p(self) -> Self {
|
|
log1p(self)
|
|
}
|
|
|
|
#[cfg(todo)]
|
|
#[inline]
|
|
fn sinh(self) -> Self {
|
|
sinh(self)
|
|
}
|
|
|
|
#[cfg(todo)]
|
|
#[inline]
|
|
fn cosh(self) -> Self {
|
|
cosh(self)
|
|
}
|
|
|
|
#[cfg(todo)]
|
|
#[inline]
|
|
fn tanh(self) -> Self {
|
|
tanh(self)
|
|
}
|
|
|
|
#[cfg(todo)]
|
|
#[inline]
|
|
fn asinh(self) -> Self {
|
|
if self == f64::NEG_INFINITY {
|
|
f64::NEG_INFINITY
|
|
} else {
|
|
(self + ((self * self) + 1.0).sqrt()).ln()
|
|
}
|
|
}
|
|
|
|
#[cfg(todo)]
|
|
#[inline]
|
|
fn acosh(self) -> Self {
|
|
match self {
|
|
x if x < 1.0 => f64::NAN,
|
|
x => (x + ((x * x) - 1.0).sqrt()).ln(),
|
|
}
|
|
}
|
|
|
|
#[cfg(todo)]
|
|
#[inline]
|
|
fn atanh(self) -> Self {
|
|
0.5 * ((2.0 * self) / (1.0 - self)).ln_1p()
|
|
}
|
|
}
|
|
|
|
mod private {
|
|
pub trait Sealed {}
|
|
|
|
impl Sealed for f32 {}
|
|
impl Sealed for f64 {}
|
|
}
|