#![no_std]
#[cfg(feature = "std")]
extern crate std;
pub const fn f32_cvt_to_int_bounds(signed: bool, out_bits: u32) -> (f32, f32) {
match (signed, out_bits) {
(true, 8) => (i8::min_value() as f32 - 1., i8::max_value() as f32 + 1.),
(true, 16) => (i16::min_value() as f32 - 1., i16::max_value() as f32 + 1.),
(true, 32) => (-2147483904.0, 2147483648.0),
(true, 64) => (-9223373136366403584.0, 9223372036854775808.0),
(false, 8) => (-1., u8::max_value() as f32 + 1.),
(false, 16) => (-1., u16::max_value() as f32 + 1.),
(false, 32) => (-1., 4294967296.0),
(false, 64) => (-1., 18446744073709551616.0),
_ => unreachable!(),
}
}
pub const fn f64_cvt_to_int_bounds(signed: bool, out_bits: u32) -> (f64, f64) {
match (signed, out_bits) {
(true, 8) => (i8::min_value() as f64 - 1., i8::max_value() as f64 + 1.),
(true, 16) => (i16::min_value() as f64 - 1., i16::max_value() as f64 + 1.),
(true, 32) => (-2147483649.0, 2147483648.0),
(true, 64) => (-9223372036854777856.0, 9223372036854775808.0),
(false, 8) => (-1., u8::max_value() as f64 + 1.),
(false, 16) => (-1., u16::max_value() as f64 + 1.),
(false, 32) => (-1., 4294967296.0),
(false, 64) => (-1., 18446744073709551616.0),
_ => unreachable!(),
}
}
pub trait WasmFloat {
fn wasm_trunc(self) -> Self;
fn wasm_copysign(self, sign: Self) -> Self;
fn wasm_floor(self) -> Self;
fn wasm_ceil(self) -> Self;
fn wasm_sqrt(self) -> Self;
fn wasm_abs(self) -> Self;
fn wasm_nearest(self) -> Self;
fn wasm_minimum(self, other: Self) -> Self;
fn wasm_maximum(self, other: Self) -> Self;
fn wasm_mul_add(self, b: Self, c: Self) -> Self;
}
impl WasmFloat for f32 {
#[inline]
fn wasm_trunc(self) -> f32 {
if self.is_nan() {
return f32::NAN;
}
#[cfg(feature = "std")]
if !cfg!(windows) && !cfg!(target_arch = "riscv64") {
return self.trunc();
}
libm::truncf(self)
}
#[inline]
fn wasm_copysign(self, sign: f32) -> f32 {
#[cfg(feature = "std")]
if true {
return self.copysign(sign);
}
libm::copysignf(self, sign)
}
#[inline]
fn wasm_floor(self) -> f32 {
if self.is_nan() {
return f32::NAN;
}
#[cfg(feature = "std")]
if !cfg!(target_arch = "riscv64") {
return self.floor();
}
libm::floorf(self)
}
#[inline]
fn wasm_ceil(self) -> f32 {
if self.is_nan() {
return f32::NAN;
}
#[cfg(feature = "std")]
if !cfg!(target_arch = "riscv64") {
return self.ceil();
}
libm::ceilf(self)
}
#[inline]
fn wasm_sqrt(self) -> f32 {
#[cfg(feature = "std")]
if true {
return self.sqrt();
}
libm::sqrtf(self)
}
#[inline]
fn wasm_abs(self) -> f32 {
#[cfg(feature = "std")]
if true {
return self.abs();
}
libm::fabsf(self)
}
#[inline]
fn wasm_nearest(self) -> f32 {
if self.is_nan() {
return f32::NAN;
}
#[cfg(feature = "std")]
if !cfg!(windows) && !cfg!(target_arch = "riscv64") {
return self.round_ties_even();
}
let round = libm::roundf(self);
if libm::fabsf(self - round) != 0.5 {
return round;
}
match round % 2.0 {
1.0 => libm::floorf(self),
-1.0 => libm::ceilf(self),
_ => round,
}
}
#[inline]
fn wasm_maximum(self, other: f32) -> f32 {
if self > other {
self
} else if other > self {
other
} else if self == other {
if self.is_sign_positive() && other.is_sign_negative() {
self
} else {
other
}
} else {
self + other
}
}
#[inline]
fn wasm_minimum(self, other: f32) -> f32 {
if self < other {
self
} else if other < self {
other
} else if self == other {
if self.is_sign_negative() && other.is_sign_positive() {
self
} else {
other
}
} else {
self + other
}
}
#[inline]
fn wasm_mul_add(self, b: f32, c: f32) -> f32 {
#[cfg(feature = "std")]
if !(cfg!(windows) && cfg!(target_env = "gnu")) {
return self.mul_add(b, c);
}
libm::fmaf(self, b, c)
}
}
impl WasmFloat for f64 {
#[inline]
fn wasm_trunc(self) -> f64 {
if self.is_nan() {
return f64::NAN;
}
#[cfg(feature = "std")]
if !cfg!(windows) && !cfg!(target_arch = "riscv64") {
return self.trunc();
}
libm::trunc(self)
}
#[inline]
fn wasm_copysign(self, sign: f64) -> f64 {
#[cfg(feature = "std")]
if true {
return self.copysign(sign);
}
libm::copysign(self, sign)
}
#[inline]
fn wasm_floor(self) -> f64 {
if self.is_nan() {
return f64::NAN;
}
#[cfg(feature = "std")]
if !cfg!(target_arch = "riscv64") {
return self.floor();
}
libm::floor(self)
}
#[inline]
fn wasm_ceil(self) -> f64 {
if self.is_nan() {
return f64::NAN;
}
#[cfg(feature = "std")]
if !cfg!(target_arch = "riscv64") {
return self.ceil();
}
libm::ceil(self)
}
#[inline]
fn wasm_sqrt(self) -> f64 {
#[cfg(feature = "std")]
if true {
return self.sqrt();
}
libm::sqrt(self)
}
#[inline]
fn wasm_abs(self) -> f64 {
#[cfg(feature = "std")]
if true {
return self.abs();
}
libm::fabs(self)
}
#[inline]
fn wasm_nearest(self) -> f64 {
if self.is_nan() {
return f64::NAN;
}
#[cfg(feature = "std")]
if !cfg!(windows) && !cfg!(target_arch = "riscv64") {
return self.round_ties_even();
}
let round = libm::round(self);
if libm::fabs(self - round) != 0.5 {
return round;
}
match round % 2.0 {
1.0 => libm::floor(self),
-1.0 => libm::ceil(self),
_ => round,
}
}
#[inline]
fn wasm_maximum(self, other: f64) -> f64 {
if self > other {
self
} else if other > self {
other
} else if self == other {
if self.is_sign_positive() && other.is_sign_negative() {
self
} else {
other
}
} else {
self + other
}
}
#[inline]
fn wasm_minimum(self, other: f64) -> f64 {
if self < other {
self
} else if other < self {
other
} else if self == other {
if self.is_sign_negative() && other.is_sign_positive() {
self
} else {
other
}
} else {
self + other
}
}
#[inline]
fn wasm_mul_add(self, b: f64, c: f64) -> f64 {
#[cfg(feature = "std")]
if !(cfg!(windows) && cfg!(target_env = "gnu")) {
return self.mul_add(b, c);
}
libm::fma(self, b, c)
}
}