use crate::{Clamp, Exp, Inv, InverseTrigonometry, Logarithm, One, Sqrt, Trigonometry, Zero};
macro_rules! impl_float {
($type:ty, $sqrt:path, $exp:path, $exp2:path, $ln:path, $log2:path, $pow:path, $sin:path, $cos:path, $tan:path,
$asin:path, $acos:path, $atan:path, $atan2:path) => {
impl Zero for $type {
fn zero() -> Self {
0.0
}
#[allow(clippy::float_cmp)]
fn is_zero(&self) -> bool {
*self == 0.0
}
}
impl One for $type {
fn one() -> Self {
1.0
}
#[allow(clippy::float_cmp)]
fn is_one(&self) -> bool {
*self == 1.0
}
}
impl Inv for $type {
type Output = Self;
fn inv(self) -> Self {
1.0 / self
}
}
impl Sqrt for $type {
fn sqrt(self) -> Self {
$sqrt(self)
}
}
impl Exp for $type {
type Output = Self;
fn exp(self) -> Self {
$exp(self)
}
fn exp2(self) -> Self {
$exp2(self)
}
}
impl Logarithm for $type {
fn ln(self) -> Self {
$ln(self)
}
fn log2(self) -> Self {
$log2(self)
}
fn powf(self, exponent: Self) -> Self {
$pow(self, exponent)
}
}
impl Trigonometry for $type {
fn sin_cos(self) -> [Self; 2] {
[$sin(self), $cos(self)]
}
fn tan(self) -> Self {
$tan(self)
}
}
impl InverseTrigonometry for $type {
fn asin(self) -> Self {
$asin(self)
}
fn acos(self) -> Self {
$acos(self)
}
fn atan(self) -> Self {
$atan(self)
}
fn atan2(self, other: Self) -> Self {
$atan2(self, other)
}
}
impl Clamp for $type {
fn min(self, other: Self) -> Self {
if self < other { self } else { other }
}
fn max(self, other: Self) -> Self {
if self > other { self } else { other }
}
}
};
}
impl_float!(
f32,
libm::sqrtf,
libm::expf,
libm::exp2f,
libm::logf,
libm::log2f,
libm::powf,
libm::sinf,
libm::cosf,
libm::tanf,
libm::asinf,
libm::acosf,
libm::atanf,
libm::atan2f
);
impl_float!(
f64,
libm::sqrt,
libm::exp,
libm::exp2,
libm::log,
libm::log2,
libm::pow,
libm::sin,
libm::cos,
libm::tan,
libm::asin,
libm::acos,
libm::atan,
libm::atan2
);
#[cfg(feature = "std")]
mod from_str_radix {
use crate::FromStrRadix;
const fn digit(c: char, radix: u32) -> Option<u32> {
let d = match c {
'0'..='9' => c as u32 - '0' as u32,
'a'..='z' => c as u32 - 'a' as u32 + 10,
'A'..='Z' => c as u32 - 'A' as u32 + 10,
_ => return None,
};
if d < radix { Some(d) } else { None }
}
macro_rules! impl_from_str_radix_float {
($($type:ty),*) => {$(
impl FromStrRadix for $type {
type Error = core::num::ParseFloatError;
#[allow(clippy::cast_possible_truncation)]
fn from_str_radix(source: &str, radix: u32) -> Result<Self, Self::Error> {
if radix == 10 {
return source.parse();
}
let s = source.strip_prefix('-').unwrap_or(source);
let negative = s.len() < source.len();
let (int_part, frac_part) = match s.split_once('.') {
Some((i, f)) => (i, Some(f)),
None => (s, None),
};
let mut value: f64 = 0.0;
for c in int_part.chars() {
let d = digit(c, radix).ok_or_else(|| "".parse::<f64>().unwrap_err())?;
value = value * f64::from(radix) + f64::from(d);
}
if let Some(frac) = frac_part {
let mut divisor = f64::from(radix);
for c in frac.chars() {
let d = digit(c, radix).ok_or_else(|| "".parse::<f64>().unwrap_err())?;
value += f64::from(d) / divisor;
divisor *= f64::from(radix);
}
}
if negative {
value = -value;
}
Ok(value as $type)
}
}
)*};
}
impl_from_str_radix_float!(f32, f64);
}