nalgebra
This commit is contained in:
14
Cargo.toml
14
Cargo.toml
@@ -10,9 +10,23 @@ license = "MIT OR Apache-2.0"
|
||||
name = "operations"
|
||||
harness = false
|
||||
|
||||
[features]
|
||||
default = ["num-traits"]
|
||||
|
||||
nalgebra-v021 = ["num-traits", "nalgebra_v021", "simba_v01", "approx_v03"]
|
||||
nalgebra-v029 = ["num-traits", "nalgebra_v029", "simba_v06", "approx_v05"]
|
||||
|
||||
[dependencies]
|
||||
num-traits = { version = "0.2", optional = true }
|
||||
|
||||
approx_v03 = { package = "approx", version = "0.3", optional = true }
|
||||
nalgebra_v021 = { package = "nalgebra", version = "0.21", optional = true }
|
||||
simba_v01 = { package = "simba", version = "0.1", optional = true }
|
||||
|
||||
approx_v05 = { package = "approx", version = "0.5", optional = true }
|
||||
nalgebra_v029 = { package = "nalgebra", version = "0.29", optional = true }
|
||||
simba_v06 = { package = "simba", version = "0.6", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = { version = "0.3", features = ["html_reports"] }
|
||||
rand = "0.8"
|
||||
|
||||
290
src/lib.rs
290
src/lib.rs
@@ -1,6 +1,7 @@
|
||||
#![doc = include_str!("../README.md")]
|
||||
#![feature(core_intrinsics)] // intrinsics for the fast math
|
||||
#![feature(asm)] // asm used to emulate freeze
|
||||
#![feature(doc_cfg)]
|
||||
use core::{
|
||||
cmp, fmt,
|
||||
intrinsics::{fadd_fast, fdiv_fast, fmul_fast, frem_fast, fsub_fast},
|
||||
@@ -9,6 +10,39 @@ use core::{
|
||||
ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign},
|
||||
};
|
||||
|
||||
macro_rules! forward_freeze_self {
|
||||
($fast_ty:ident, $base_ty:ident
|
||||
$(
|
||||
$(#[$attr:meta])*
|
||||
$vis:vis fn $fn_name:ident (self $(, $arg:ident : Self)* ) -> Self ;
|
||||
)*) => {
|
||||
$(
|
||||
$(#[$attr])*
|
||||
#[inline]
|
||||
$vis fn $fn_name(self $(, $arg : Self)*) -> Self {
|
||||
<$fast_ty>::new(<$base_ty>::$fn_name(self.freeze_raw() $(, $arg.freeze_raw())* ))
|
||||
}
|
||||
)*
|
||||
};
|
||||
|
||||
($fast_ty:ident, $base_ty:ident
|
||||
$(
|
||||
$(#[$attr:meta])*
|
||||
$vis:vis fn $fn_name:ident (&self $(, $arg:ident : &Self)* ) -> Self ;
|
||||
)*) => {
|
||||
$(
|
||||
$(#[$attr])*
|
||||
#[inline]
|
||||
$vis fn $fn_name(&self $(, $arg : &Self)*) -> Self {
|
||||
<$fast_ty>::new(<$base_ty>::$fn_name(self.freeze_raw() $(, $arg.freeze_raw())* ))
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
mod nalgebra;
|
||||
mod num_traits;
|
||||
|
||||
mod poison;
|
||||
use poison::MaybePoison;
|
||||
|
||||
@@ -266,259 +300,6 @@ macro_rules! impl_fmt {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "num-traits")]
|
||||
macro_rules! impl_num_traits {
|
||||
($fast_ty:ident, $base_ty:ident) => {
|
||||
impl num_traits::One for $fast_ty {
|
||||
#[inline(always)]
|
||||
fn one() -> Self {
|
||||
Self::ONE
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_one(&self) -> bool {
|
||||
self.freeze_raw() == 1.0
|
||||
}
|
||||
}
|
||||
|
||||
impl num_traits::Zero for $fast_ty {
|
||||
#[inline(always)]
|
||||
fn zero() -> Self {
|
||||
Self::ZERO
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_zero(&self) -> bool {
|
||||
self.freeze_raw() == 0.0
|
||||
}
|
||||
}
|
||||
|
||||
impl num_traits::Num for $fast_ty {
|
||||
type FromStrRadixErr = <$base_ty as num_traits::Num>::FromStrRadixErr;
|
||||
|
||||
fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
|
||||
Ok(<$fast_ty>::new(
|
||||
<$base_ty as num_traits::Num>::from_str_radix(str, radix)?,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl num_traits::ToPrimitive for $fast_ty {
|
||||
forward_freeze_ty! {
|
||||
$fast_ty, $base_ty
|
||||
fn to_isize(&self) -> Option<isize> ;
|
||||
fn to_i8(&self) -> Option<i8> ;
|
||||
fn to_i16(&self) -> Option<i16> ;
|
||||
fn to_i32(&self) -> Option<i32> ;
|
||||
fn to_i64(&self) -> Option<i64> ;
|
||||
fn to_i128(&self) -> Option<i128> ;
|
||||
|
||||
fn to_usize(&self) -> Option<usize> ;
|
||||
fn to_u8(&self) -> Option<u8> ;
|
||||
fn to_u16(&self) -> Option<u16> ;
|
||||
fn to_u32(&self) -> Option<u32> ;
|
||||
fn to_u64(&self) -> Option<u64> ;
|
||||
fn to_u128(&self) -> Option<u128> ;
|
||||
|
||||
fn to_f32(&self) -> Option<f32> ;
|
||||
fn to_f64(&self) -> Option<f64> ;
|
||||
}
|
||||
}
|
||||
|
||||
impl num_traits::NumCast for $fast_ty {
|
||||
#[inline]
|
||||
fn from<N: num_traits::ToPrimitive>(n: N) -> Option<Self> {
|
||||
Some(<$fast_ty>::new(<$base_ty as num_traits::NumCast>::from(n)?))
|
||||
}
|
||||
}
|
||||
|
||||
/// Because inf and nan are prohibited, the `fast_fp` types correspond more to the `Real`
|
||||
/// trait than the `Float` trait. However in practice some libs require a Float bound when
|
||||
/// they could really use a Real, which would restrict using the `fast_fp` types.
|
||||
impl num_traits::Float for $fast_ty {
|
||||
/// Panics because NaN values are not supported
|
||||
#[inline]
|
||||
fn nan() -> Self {
|
||||
panic!(concat!(
|
||||
stringify!($fast_ty),
|
||||
" does not support NaN values"
|
||||
));
|
||||
}
|
||||
|
||||
/// Panics because infinite values are not supported
|
||||
///
|
||||
/// Consider using [`max_value`](num_traits::Float::max_value) as appropriate instead
|
||||
#[inline]
|
||||
fn infinity() -> Self {
|
||||
panic!(concat!(
|
||||
stringify!($fast_ty),
|
||||
" does not support infinite values. Consider using `max_value` for comparisons"
|
||||
));
|
||||
}
|
||||
|
||||
/// Panics because infinite values are not supported
|
||||
///
|
||||
/// Consider using [`min_value`](num_traits::Float::min_value) as appropriate instead
|
||||
#[inline]
|
||||
fn neg_infinity() -> Self {
|
||||
panic!(concat!(
|
||||
stringify!($fast_ty),
|
||||
" does not support infinite values. Consider using `min_value` for comparisons"
|
||||
));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn neg_zero() -> Self {
|
||||
-Self::ZERO
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn min_value() -> Self {
|
||||
$fast_ty::MIN
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn min_positive_value() -> Self {
|
||||
$fast_ty::MIN_POSITIVE
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn max_value() -> Self {
|
||||
$fast_ty::MAX
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn epsilon() -> Self {
|
||||
<$fast_ty>::new($base_ty::EPSILON)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_nan(self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_infinite(self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_finite(self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
forward_self! {
|
||||
$fast_ty, $base_ty
|
||||
fn is_normal(self) -> bool;
|
||||
fn classify(self) -> FpCategory;
|
||||
fn floor(self) -> Self;
|
||||
fn ceil(self) -> Self;
|
||||
fn round(self) -> Self;
|
||||
fn trunc(self) -> Self;
|
||||
fn fract(self) -> Self;
|
||||
fn abs(self) -> Self;
|
||||
fn signum(self) -> Self;
|
||||
fn is_sign_positive(self) -> bool;
|
||||
fn is_sign_negative(self) -> bool;
|
||||
fn mul_add(self, a: Self, b: Self) -> Self;
|
||||
fn recip(self) -> Self;
|
||||
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 max(self, other: Self) -> Self;
|
||||
fn min(self, other: 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 to_degrees(self) -> Self;
|
||||
fn to_radians(self) -> Self;
|
||||
}
|
||||
|
||||
forward_freeze_self! {
|
||||
$fast_ty, $base_ty
|
||||
#[allow(deprecated)]
|
||||
fn abs_sub(self, other: Self) -> Self;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn integer_decode(self) -> (u64, i16, i8) {
|
||||
<$base_ty as num_traits::Float>::integer_decode(self.freeze_raw())
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! forward_freeze_self {
|
||||
($fast_ty:ident, $base_ty:ident
|
||||
$(
|
||||
$(#[$attr:meta])*
|
||||
$vis:vis fn $fn_name:ident (self $(, $arg:ident : Self)* ) -> Self ;
|
||||
)*) => {
|
||||
$(
|
||||
$(#[$attr])*
|
||||
#[inline]
|
||||
$vis fn $fn_name(self $(, $arg : Self)*) -> Self {
|
||||
<$fast_ty>::new(<$base_ty>::$fn_name(self.freeze_raw() $(, $arg.freeze_raw())* ))
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "num-traits")]
|
||||
macro_rules! forward_freeze_ty {
|
||||
($fast_ty:ident, $base_ty:ident
|
||||
$(
|
||||
$(#[$attr:meta])*
|
||||
$vis:vis fn $fn_name:ident (&self) -> $ret_ty:ty ;
|
||||
)*) => {
|
||||
$(
|
||||
$(#[$attr])*
|
||||
#[inline]
|
||||
$vis fn $fn_name(&self) -> $ret_ty {
|
||||
<$base_ty>::$fn_name(&self.freeze_raw())
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "num-traits")]
|
||||
macro_rules! forward_self {
|
||||
($fast_ty:ident, $base_ty:ident
|
||||
$(
|
||||
$(#[$attr:meta])*
|
||||
$vis:vis fn $fn_name:ident (self $(, $arg:ident : $arg_ty:ty)* ) -> $ret_ty:ty ;
|
||||
)*) => {
|
||||
$(
|
||||
$(#[$attr])*
|
||||
#[inline]
|
||||
$vis fn $fn_name(self $(, $arg : $arg_ty)*) -> $ret_ty {
|
||||
<$fast_ty>::$fn_name(self $(, $arg)* )
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impls {
|
||||
($fast_ty:ident, $base_ty: ident) => {
|
||||
impl $fast_ty {
|
||||
@@ -839,9 +620,6 @@ macro_rules! impls {
|
||||
<$fast_ty>::new(from)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "num-traits")]
|
||||
impl_num_traits! { $fast_ty, $base_ty }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
422
src/nalgebra.rs
Normal file
422
src/nalgebra.rs
Normal file
@@ -0,0 +1,422 @@
|
||||
#![cfg(any(feature = "nalgebra-v021"))]
|
||||
macro_rules! forward_fn_const {
|
||||
($fast_ty:ident, $base_ty:ident
|
||||
$(fn $fn_name:ident () -> Self ;)*) => {
|
||||
$(
|
||||
fn $fn_name () -> $fast_ty {
|
||||
<$fast_ty>::new(<$base_ty>::$fn_name())
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_nalgebra {
|
||||
($($fast_ty:ident, $base_ty:ident),* ;
|
||||
$nalgebra_version:path, $simba_version:path, $approx_version:path ;
|
||||
@RealField: $real_field_callback:ident
|
||||
) => {
|
||||
use $crate::{FF32, FF64, num_traits::forward_self};
|
||||
use $nalgebra_version as na;
|
||||
use $simba_version as simba;
|
||||
use $approx_version as approx;
|
||||
|
||||
$(
|
||||
impl simba::simd::SimdValue for $fast_ty {
|
||||
type Element = Self;
|
||||
type SimdBool = bool;
|
||||
|
||||
#[inline]
|
||||
fn lanes() -> usize {
|
||||
1
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn splat(val: Self::Element) -> Self {
|
||||
val
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn extract(&self, _:usize) -> Self::Element {
|
||||
*self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn extract_unchecked(&self, _:usize) -> Self::Element {
|
||||
*self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn replace(&mut self, _:usize, val: Self::Element) {
|
||||
*self = val
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn replace_unchecked(&mut self, _:usize, val: Self::Element) {
|
||||
*self = val
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn select(self, cond:Self::SimdBool, other: Self) -> Self {
|
||||
if cond {
|
||||
self
|
||||
} else {
|
||||
other
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl simba::scalar::SubsetOf<f32> for $fast_ty {
|
||||
#[inline]
|
||||
fn to_superset(&self) -> f32 {
|
||||
self.freeze_raw() as f32
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_superset_unchecked(element: &f32) -> Self {
|
||||
<$fast_ty>::new(*element as $base_ty)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_in_subset(_: &f32) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl simba::scalar::SubsetOf<f64> for $fast_ty {
|
||||
#[inline]
|
||||
fn to_superset(&self) -> f64 {
|
||||
self.freeze_raw() as f64
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_superset_unchecked(element: &f64) -> Self {
|
||||
<$fast_ty>::new(*element as $base_ty)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_in_subset(_: &f64) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl simba::scalar::SubsetOf<FF32> for $fast_ty {
|
||||
#[inline]
|
||||
fn to_superset(&self) -> FF32 {
|
||||
FF32::new(self.freeze_raw() as f32)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_superset_unchecked(element: &FF32) -> Self {
|
||||
<$fast_ty>::new(element.freeze_raw() as $base_ty)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_in_subset(_: &FF32) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl simba::scalar::SubsetOf<FF64> for $fast_ty {
|
||||
#[inline]
|
||||
fn to_superset(&self) -> FF64 {
|
||||
FF64::new(self.freeze_raw() as f64)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_superset_unchecked(element: &FF64) -> Self {
|
||||
<$fast_ty>::new(element.freeze_raw() as $base_ty)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_in_subset(_: &FF64) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl simba::scalar::SubsetOf<$fast_ty> for f32 {
|
||||
#[inline]
|
||||
fn to_superset(&self) -> $fast_ty {
|
||||
<$fast_ty>::new(*self as $base_ty)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_superset_unchecked(element: &$fast_ty) -> Self {
|
||||
element.freeze_raw() as f32
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_in_subset(_: &$fast_ty) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl simba::scalar::SubsetOf<$fast_ty> for f64 {
|
||||
#[inline]
|
||||
fn to_superset(&self) -> $fast_ty {
|
||||
<$fast_ty>::new(*self as $base_ty)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_superset_unchecked(element: &$fast_ty) -> Self {
|
||||
element.freeze_raw() as f64
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_in_subset(_: &$fast_ty) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl approx::AbsDiffEq for $fast_ty {
|
||||
type Epsilon = Self;
|
||||
|
||||
#[inline]
|
||||
fn default_epsilon() -> Self {
|
||||
<$fast_ty>::new($base_ty::EPSILON)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn abs_diff_eq(&self, other: &Self, epsilon: Self) -> bool {
|
||||
<$fast_ty>::abs(self - other) <= epsilon
|
||||
}
|
||||
}
|
||||
|
||||
impl approx::UlpsEq for $fast_ty {
|
||||
#[inline]
|
||||
fn default_max_ulps() -> u32 {
|
||||
<$base_ty>::default_max_ulps()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn ulps_eq(&self, other: &Self, epsilon: Self, max_ulps: u32) -> bool {
|
||||
<$base_ty>::ulps_eq(
|
||||
&self.freeze_raw(),
|
||||
&other.freeze_raw(),
|
||||
epsilon.freeze_raw(),
|
||||
max_ulps
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl approx::RelativeEq for $fast_ty {
|
||||
#[inline]
|
||||
fn default_max_relative() -> Self::Epsilon {
|
||||
<$fast_ty as approx::AbsDiffEq>::default_epsilon()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn relative_eq(&self, other: &Self, epsilon: Self, max_relative: Self) -> bool {
|
||||
<$base_ty>::relative_eq(
|
||||
&self.freeze_raw(),
|
||||
&other.freeze_raw(),
|
||||
epsilon.freeze_raw(),
|
||||
max_relative.freeze_raw(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl na::Field for $fast_ty {}
|
||||
|
||||
impl na::RealField for $fast_ty {
|
||||
forward_self! {
|
||||
$fast_ty, $base_ty
|
||||
fn atan2(self, other: Self) -> Self;
|
||||
fn clamp(self, min: Self, max: Self) -> Self;
|
||||
fn max(self, other: Self) -> Self;
|
||||
fn min(self, other: Self) -> Self;
|
||||
}
|
||||
|
||||
forward_fn_const! {
|
||||
$fast_ty, $base_ty
|
||||
fn pi() -> Self ;
|
||||
fn two_pi() -> Self ;
|
||||
fn frac_pi_2() -> Self ;
|
||||
fn frac_pi_3() -> Self ;
|
||||
fn frac_pi_4() -> Self ;
|
||||
fn frac_pi_6() -> Self ;
|
||||
fn frac_pi_8() -> Self ;
|
||||
fn frac_1_pi() -> Self ;
|
||||
fn frac_2_pi() -> Self ;
|
||||
fn frac_2_sqrt_pi() -> Self ;
|
||||
fn e() -> Self ;
|
||||
fn log2_e() -> Self ;
|
||||
fn log10_e() -> Self ;
|
||||
fn ln_2() -> Self ;
|
||||
fn ln_10() -> Self ;
|
||||
}
|
||||
|
||||
$real_field_callback! { $fast_ty, $base_ty }
|
||||
}
|
||||
|
||||
impl na::ComplexField for $fast_ty {
|
||||
type RealField = Self;
|
||||
|
||||
forward_self! {
|
||||
$fast_ty, $base_ty
|
||||
fn floor(self) -> Self;
|
||||
fn ceil(self) -> Self;
|
||||
fn round(self) -> Self;
|
||||
fn trunc(self) -> Self;
|
||||
fn fract(self) -> Self;
|
||||
fn abs(self) -> Self;
|
||||
fn signum(self) -> Self;
|
||||
fn mul_add(self, a: Self, b: Self) -> Self;
|
||||
fn recip(self) -> Self;
|
||||
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 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;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_real(re: Self::RealField) -> Self {
|
||||
re
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn real(self) -> Self::RealField {
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn imaginary(self) -> Self::RealField {
|
||||
Self::ZERO
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn norm1(self) -> Self::RealField {
|
||||
self.abs()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn modulus(self) -> Self::RealField {
|
||||
self.abs()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn modulus_squared(self) -> Self::RealField {
|
||||
self * self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn argument(self) -> Self::RealField {
|
||||
if self >= Self::ZERO {
|
||||
Self::ZERO
|
||||
} else {
|
||||
<$fast_ty>::new(core::$base_ty::consts::PI)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn scale(self, factor: Self::RealField) -> Self {
|
||||
self * factor
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn unscale(self, factor: Self::RealField) -> Self {
|
||||
self / factor
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn conjugate(self) -> Self {
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn powc(self, n: Self) -> Self {
|
||||
self.powf(n)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_finite(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn try_sqrt(self) -> Option<Self> {
|
||||
let x = self.freeze_raw();
|
||||
if x > 0.0 {
|
||||
Some(<$fast_ty>::new(x.sqrt()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "nalgebra-v021")]
|
||||
#[doc(cfg(feature = "nalgebra-v021"))]
|
||||
mod nalgebra_v021 {
|
||||
macro_rules! real_field {
|
||||
($fast_ty:ident, $base_ty:ident) => {
|
||||
#[inline]
|
||||
fn is_sign_positive(self) -> bool {
|
||||
self > Self::ZERO
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_sign_negative(self) -> bool {
|
||||
self < Self::ZERO
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_nalgebra! {
|
||||
FF32, f32, FF64, f64 ;
|
||||
::nalgebra_v021, ::simba_v01, ::approx_v03 ;
|
||||
@RealField: real_field
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "nalgebra-v029")]
|
||||
#[doc(cfg(feature = "nalgebra-v029"))]
|
||||
mod nalgebra_v029 {
|
||||
macro_rules! real_field {
|
||||
($fast_ty:ident, $base_ty:ident) => {
|
||||
#[inline]
|
||||
fn is_sign_positive(&self) -> bool {
|
||||
*self > Self::ZERO
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_sign_negative(&self) -> bool {
|
||||
*self < Self::ZERO
|
||||
}
|
||||
|
||||
forward_self! {
|
||||
$fast_ty, $base_ty
|
||||
fn copysign(self, other: Self) -> Self;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_nalgebra! {
|
||||
FF32, f32, FF64, f64 ;
|
||||
::nalgebra_v029, ::simba_v06, ::approx_v05 ;
|
||||
@RealField: real_field
|
||||
}
|
||||
}
|
||||
330
src/num_traits.rs
Normal file
330
src/num_traits.rs
Normal file
@@ -0,0 +1,330 @@
|
||||
#![cfg(feature = "num-traits")]
|
||||
#![doc(cfg(feature = "num-traits"))]
|
||||
use crate::{FF32, FF64};
|
||||
use core::num::FpCategory;
|
||||
|
||||
macro_rules! forward_freeze_ty {
|
||||
($fast_ty:ident, $base_ty:ident
|
||||
$(
|
||||
$(#[$attr:meta])*
|
||||
$vis:vis fn $fn_name:ident (&self) -> $ret_ty:ty ;
|
||||
)*) => {
|
||||
$(
|
||||
$(#[$attr])*
|
||||
#[inline]
|
||||
$vis fn $fn_name(&self) -> $ret_ty {
|
||||
<$base_ty>::$fn_name(&self.freeze_raw())
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! forward_self {
|
||||
($fast_ty:ident, $base_ty:ident
|
||||
$(
|
||||
$(#[$attr:meta])*
|
||||
$vis:vis fn $fn_name:ident (self $(, $arg:ident : $arg_ty:ty)* ) -> $ret_ty:ty ;
|
||||
)*) => {
|
||||
$(
|
||||
$(#[$attr])*
|
||||
#[inline]
|
||||
$vis fn $fn_name(self $(, $arg : $arg_ty)*) -> $ret_ty {
|
||||
<$fast_ty>::$fn_name(self $(, $arg)* )
|
||||
}
|
||||
)*
|
||||
};
|
||||
|
||||
($fast_ty:ident, $base_ty:ident
|
||||
$(
|
||||
$(#[$attr:meta])*
|
||||
$vis:vis fn $fn_name:ident (&self $(, $arg:ident : $arg_ty:ty)* ) -> $ret_ty:ty ;
|
||||
)*) => {
|
||||
$(
|
||||
$(#[$attr])*
|
||||
#[inline]
|
||||
$vis fn $fn_name(&self $(, $arg : $arg_ty)*) -> $ret_ty {
|
||||
<$fast_ty>::$fn_name(*self $(, $arg)* )
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) use forward_self;
|
||||
|
||||
macro_rules! opt_from_base {
|
||||
($fast_ty:ident, $base_ty:ident
|
||||
$(
|
||||
$(#[$attr:meta])*
|
||||
$vis:vis fn $fn_name:ident ($($arg:ident : $arg_ty:ty),*) -> Option<Self> ;
|
||||
)*) => {
|
||||
$(
|
||||
$(#[$attr])*
|
||||
#[inline]
|
||||
$vis fn $fn_name($($arg : $arg_ty),*) -> Option<Self> {
|
||||
Some(<$fast_ty>::new(<$base_ty>::$fn_name($($arg),*)?))
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_num_traits {
|
||||
($fast_ty:ident, $base_ty:ident) => {
|
||||
impl num_traits::One for $fast_ty {
|
||||
#[inline(always)]
|
||||
fn one() -> Self {
|
||||
Self::ONE
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_one(&self) -> bool {
|
||||
self.freeze_raw() == 1.0
|
||||
}
|
||||
}
|
||||
|
||||
impl num_traits::Zero for $fast_ty {
|
||||
#[inline(always)]
|
||||
fn zero() -> Self {
|
||||
Self::ZERO
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_zero(&self) -> bool {
|
||||
self.freeze_raw() == 0.0
|
||||
}
|
||||
}
|
||||
|
||||
impl num_traits::Bounded for $fast_ty {
|
||||
#[inline]
|
||||
fn max_value() -> Self {
|
||||
Self::MAX
|
||||
}
|
||||
#[inline]
|
||||
fn min_value() -> Self {
|
||||
Self::MIN
|
||||
}
|
||||
}
|
||||
|
||||
impl num_traits::Signed for $fast_ty {
|
||||
forward_self! {
|
||||
$fast_ty, $base_ty
|
||||
fn abs(&self) -> Self ;
|
||||
fn signum(&self) -> Self ;
|
||||
}
|
||||
|
||||
forward_freeze_self! {
|
||||
$fast_ty, $base_ty
|
||||
#[allow(deprecated)]
|
||||
fn abs_sub(&self, other: &Self) -> Self;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_positive(&self) -> bool {
|
||||
self.freeze_raw() > 0.0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_negative(&self) -> bool {
|
||||
self.freeze_raw() < 0.0
|
||||
}
|
||||
}
|
||||
|
||||
impl num_traits::Num for $fast_ty {
|
||||
type FromStrRadixErr = <$base_ty as num_traits::Num>::FromStrRadixErr;
|
||||
|
||||
fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
|
||||
Ok(<$fast_ty>::new(
|
||||
<$base_ty as num_traits::Num>::from_str_radix(str, radix)?,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl num_traits::ToPrimitive for $fast_ty {
|
||||
forward_freeze_ty! {
|
||||
$fast_ty, $base_ty
|
||||
fn to_isize(&self) -> Option<isize> ;
|
||||
fn to_i8(&self) -> Option<i8> ;
|
||||
fn to_i16(&self) -> Option<i16> ;
|
||||
fn to_i32(&self) -> Option<i32> ;
|
||||
fn to_i64(&self) -> Option<i64> ;
|
||||
fn to_i128(&self) -> Option<i128> ;
|
||||
|
||||
fn to_usize(&self) -> Option<usize> ;
|
||||
fn to_u8(&self) -> Option<u8> ;
|
||||
fn to_u16(&self) -> Option<u16> ;
|
||||
fn to_u32(&self) -> Option<u32> ;
|
||||
fn to_u64(&self) -> Option<u64> ;
|
||||
fn to_u128(&self) -> Option<u128> ;
|
||||
|
||||
fn to_f32(&self) -> Option<f32> ;
|
||||
fn to_f64(&self) -> Option<f64> ;
|
||||
}
|
||||
}
|
||||
|
||||
impl num_traits::FromPrimitive for $fast_ty {
|
||||
opt_from_base! {
|
||||
$fast_ty, $base_ty
|
||||
fn from_isize(n: isize) -> Option<Self> ;
|
||||
fn from_i8(n: i8) -> Option<Self> ;
|
||||
fn from_i16(n: i16) -> Option<Self> ;
|
||||
fn from_i32(n: i32) -> Option<Self> ;
|
||||
fn from_i64(n: i64) -> Option<Self> ;
|
||||
fn from_i128(n: i128) -> Option<Self> ;
|
||||
|
||||
fn from_usize(n: usize) -> Option<Self> ;
|
||||
fn from_u8(n: u8) -> Option<Self> ;
|
||||
fn from_u16(n: u16) -> Option<Self> ;
|
||||
fn from_u32(n: u32) -> Option<Self> ;
|
||||
fn from_u64(n: u64) -> Option<Self> ;
|
||||
fn from_u128(n: u128) -> Option<Self> ;
|
||||
|
||||
fn from_f32(n: f32) -> Option<Self> ;
|
||||
fn from_f64(n: f64) -> Option<Self> ;
|
||||
}
|
||||
}
|
||||
|
||||
impl num_traits::NumCast for $fast_ty {
|
||||
#[inline]
|
||||
fn from<N: num_traits::ToPrimitive>(n: N) -> Option<Self> {
|
||||
Some(<$fast_ty>::new(<$base_ty as num_traits::NumCast>::from(n)?))
|
||||
}
|
||||
}
|
||||
|
||||
/// Because inf and nan are prohibited, the `fast_fp` types correspond more to the `Real`
|
||||
/// trait than the `Float` trait. However in practice some libs require a Float bound when
|
||||
/// they could really use a Real, which would restrict using the `fast_fp` types.
|
||||
impl num_traits::Float for $fast_ty {
|
||||
/// Panics because NaN values are not supported
|
||||
#[inline]
|
||||
fn nan() -> Self {
|
||||
panic!(concat!(
|
||||
stringify!($fast_ty),
|
||||
" does not support NaN values"
|
||||
));
|
||||
}
|
||||
|
||||
/// Panics because infinite values are not supported
|
||||
///
|
||||
/// Consider using [`max_value`](num_traits::Float::max_value) as appropriate instead
|
||||
#[inline]
|
||||
fn infinity() -> Self {
|
||||
panic!(concat!(
|
||||
stringify!($fast_ty),
|
||||
" does not support infinite values. Consider using `max_value` for comparisons"
|
||||
));
|
||||
}
|
||||
|
||||
/// Panics because infinite values are not supported
|
||||
///
|
||||
/// Consider using [`min_value`](num_traits::Float::min_value) as appropriate instead
|
||||
#[inline]
|
||||
fn neg_infinity() -> Self {
|
||||
panic!(concat!(
|
||||
stringify!($fast_ty),
|
||||
" does not support infinite values. Consider using `min_value` for comparisons"
|
||||
));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn neg_zero() -> Self {
|
||||
-Self::ZERO
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn min_value() -> Self {
|
||||
$fast_ty::MIN
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn min_positive_value() -> Self {
|
||||
$fast_ty::MIN_POSITIVE
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn max_value() -> Self {
|
||||
$fast_ty::MAX
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn epsilon() -> Self {
|
||||
<$fast_ty>::new($base_ty::EPSILON)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_nan(self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_infinite(self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_finite(self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
forward_self! {
|
||||
$fast_ty, $base_ty
|
||||
fn is_normal(self) -> bool;
|
||||
fn classify(self) -> FpCategory;
|
||||
fn floor(self) -> Self;
|
||||
fn ceil(self) -> Self;
|
||||
fn round(self) -> Self;
|
||||
fn trunc(self) -> Self;
|
||||
fn fract(self) -> Self;
|
||||
fn abs(self) -> Self;
|
||||
fn signum(self) -> Self;
|
||||
fn is_sign_positive(self) -> bool;
|
||||
fn is_sign_negative(self) -> bool;
|
||||
fn mul_add(self, a: Self, b: Self) -> Self;
|
||||
fn recip(self) -> Self;
|
||||
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 max(self, other: Self) -> Self;
|
||||
fn min(self, other: 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 to_degrees(self) -> Self;
|
||||
fn to_radians(self) -> Self;
|
||||
}
|
||||
|
||||
forward_freeze_self! {
|
||||
$fast_ty, $base_ty
|
||||
#[allow(deprecated)]
|
||||
fn abs_sub(self, other: Self) -> Self;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn integer_decode(self) -> (u64, i16, i8) {
|
||||
<$base_ty as num_traits::Float>::integer_decode(self.freeze_raw())
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_num_traits! { FF32, f32 }
|
||||
impl_num_traits! { FF64, f64 }
|
||||
Reference in New Issue
Block a user