rename 'coremem_types' -> 'coremem_cross' to better reflect its purpose
This commit is contained in:
498
crates/cross/src/real.rs
Normal file
498
crates/cross/src/real.rs
Normal file
@@ -0,0 +1,498 @@
|
||||
use core::intrinsics;
|
||||
use core::ops::{
|
||||
Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign,
|
||||
};
|
||||
use core::cmp::{Eq, Ord, Ordering, PartialOrd};
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
#[cfg(feature = "fmt")]
|
||||
use core::fmt;
|
||||
|
||||
pub trait ToFloat {
|
||||
// TODO: make these by-value
|
||||
fn to_f32(&self) -> f32 {
|
||||
self.to_f64() as _
|
||||
}
|
||||
fn to_f64(&self) -> f64 {
|
||||
self.to_f32() as _
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "fmt")]
|
||||
pub trait RealFeatures: fmt::LowerExp + fmt::Display + fmt::Debug {}
|
||||
#[cfg(not(feature = "fmt"))]
|
||||
pub trait RealFeatures {}
|
||||
|
||||
/// This exists to allow configuration over # of bits (f32 v.s. f64) as well as
|
||||
/// constraints.
|
||||
pub trait Real:
|
||||
ToFloat
|
||||
+ RealFeatures
|
||||
+ PartialOrd
|
||||
+ Add<Output=Self>
|
||||
+ Sub<Output=Self>
|
||||
+ Mul<Output=Self>
|
||||
+ Div<Output=Self>
|
||||
+ AddAssign
|
||||
+ MulAssign
|
||||
+ SubAssign
|
||||
+ DivAssign
|
||||
+ Neg<Output=Self>
|
||||
+ Copy
|
||||
+ Clone
|
||||
+ Default
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static {
|
||||
// TODO: fold with from_<blah>
|
||||
fn from_primitive<P: ToFloat>(p: P) -> Self {
|
||||
Self::from_f64(p.to_f64())
|
||||
}
|
||||
|
||||
fn from_f32(f: f32) -> Self {
|
||||
Self::from_f64(f as _)
|
||||
}
|
||||
fn from_f64(f: f64) -> Self {
|
||||
Self::from_f32(f as _)
|
||||
}
|
||||
fn from_u64(u: u64) -> Self {
|
||||
Self::from_primitive(u)
|
||||
}
|
||||
fn from_u32(u: u32) -> Self {
|
||||
Self::from_primitive(u)
|
||||
}
|
||||
|
||||
// TODO: make this by-value
|
||||
fn cast<R: Real>(&self) -> R {
|
||||
R::from_primitive(*self)
|
||||
}
|
||||
|
||||
fn is_finite(self) -> bool;
|
||||
fn floor(self) -> Self;
|
||||
fn ceil(self) -> Self;
|
||||
fn round(self) -> Self;
|
||||
fn abs(self) -> Self;
|
||||
fn exp(self) -> Self;
|
||||
fn powf(self, p: Self) -> Self;
|
||||
fn sqrt(self) -> Self;
|
||||
fn sin_cos(self) -> (Self, Self);
|
||||
|
||||
fn min_max_or_undefined(self, other: Self) -> (Self, Self) {
|
||||
match self.partial_cmp(&other) {
|
||||
Some(ordering) => match ordering {
|
||||
Ordering::Less | Ordering::Equal => (self, other),
|
||||
_ => (other, self),
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
fn min_or_undefined(self, other: Self) -> Self {
|
||||
self.min_max_or_undefined(other).0
|
||||
}
|
||||
fn max_or_undefined(self, other: Self) -> Self {
|
||||
self.min_max_or_undefined(other).1
|
||||
}
|
||||
|
||||
fn is_zero(self) -> bool {
|
||||
self == Self::zero()
|
||||
}
|
||||
|
||||
fn zero() -> Self;
|
||||
fn one() -> Self;
|
||||
fn two() -> Self;
|
||||
fn three() -> Self;
|
||||
fn ten() -> Self;
|
||||
fn tenth() -> Self;
|
||||
fn third() -> Self;
|
||||
fn half() -> Self;
|
||||
fn pi() -> Self;
|
||||
fn two_pi() -> Self;
|
||||
|
||||
/// Speed of light in a vacuum; m/s.
|
||||
/// Also equal to 1/sqrt(epsilon_0 mu_0)
|
||||
fn c() -> Self;
|
||||
/// Vaccum Permittivity
|
||||
fn eps0() -> Self;
|
||||
fn twice_eps0() -> Self;
|
||||
/// Vacuum Permeability
|
||||
fn mu0() -> Self;
|
||||
fn mu0_inv() -> Self;
|
||||
}
|
||||
|
||||
macro_rules! decl_consts {
|
||||
($wrap:expr) => {
|
||||
fn zero() -> Self {
|
||||
$wrap(0.0)
|
||||
}
|
||||
fn one() -> Self {
|
||||
$wrap(1.0)
|
||||
}
|
||||
fn two() -> Self {
|
||||
$wrap(2.0)
|
||||
}
|
||||
fn three() -> Self {
|
||||
$wrap(3.0)
|
||||
}
|
||||
fn ten() -> Self {
|
||||
$wrap(10.0)
|
||||
}
|
||||
fn tenth() -> Self {
|
||||
$wrap(0.1)
|
||||
}
|
||||
fn third() -> Self {
|
||||
$wrap(0.3333333333333333)
|
||||
}
|
||||
fn half() -> Self {
|
||||
$wrap(0.5)
|
||||
}
|
||||
|
||||
fn pi() -> Self {
|
||||
$wrap(3.141592653589793)
|
||||
}
|
||||
fn two_pi() -> Self {
|
||||
$wrap(6.283185307179586)
|
||||
}
|
||||
|
||||
/// Speed of light in a vacuum; m/s.
|
||||
/// Also equal to 1/sqrt(epsilon_0 mu_0)
|
||||
fn c() -> Self {
|
||||
$wrap(299792458.0)
|
||||
}
|
||||
/// Vaccum Permittivity
|
||||
fn eps0() -> Self {
|
||||
$wrap(8.854187812813e-12) // F⋅m−1
|
||||
}
|
||||
fn twice_eps0() -> Self {
|
||||
$wrap(1.7708375625626e-11) // F⋅m−1
|
||||
}
|
||||
/// Vacuum Permeability
|
||||
fn mu0() -> Self {
|
||||
$wrap(1.2566370621219e-6) // H/m
|
||||
}
|
||||
fn mu0_inv() -> Self {
|
||||
$wrap(795774.715025073) // m/H
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl ToFloat for f32 {
|
||||
fn to_f32(&self) -> f32 {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl RealFeatures for f32 {}
|
||||
|
||||
impl Real for f32 {
|
||||
decl_consts!(Real::from_f32);
|
||||
fn from_primitive<P: ToFloat>(p: P) -> Self {
|
||||
Self::from_f32(p.to_f32())
|
||||
}
|
||||
fn from_f32(f: f32) -> Self {
|
||||
f
|
||||
}
|
||||
fn is_finite(self) -> bool {
|
||||
f32::is_finite(self)
|
||||
}
|
||||
fn floor(self) -> Self {
|
||||
unsafe { intrinsics::floorf32(self) }
|
||||
}
|
||||
fn ceil(self) -> Self {
|
||||
unsafe { intrinsics::ceilf32(self) }
|
||||
}
|
||||
fn round(self) -> Self {
|
||||
unsafe { intrinsics::roundf32(self) }
|
||||
}
|
||||
fn abs(self) -> Self {
|
||||
unsafe { intrinsics::fabsf32(self) }
|
||||
}
|
||||
fn exp(self) -> Self {
|
||||
unsafe { intrinsics::expf32(self) }
|
||||
}
|
||||
fn sqrt(self) -> Self {
|
||||
unsafe { intrinsics::sqrtf32(self) }
|
||||
}
|
||||
fn powf(self, p: Self) -> Self {
|
||||
unsafe { intrinsics::powf32(self, p) }
|
||||
}
|
||||
fn sin_cos(self) -> (Self, Self) {
|
||||
unsafe {(
|
||||
intrinsics::sinf32(self),
|
||||
intrinsics::cosf32(self),
|
||||
)}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToFloat for f64 {
|
||||
fn to_f64(&self) -> f64 {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl RealFeatures for f64 {}
|
||||
|
||||
impl Real for f64 {
|
||||
decl_consts!(Real::from_f64);
|
||||
fn from_f64(f: f64) -> Self {
|
||||
f
|
||||
}
|
||||
fn is_finite(self) -> bool {
|
||||
f64::is_finite(self)
|
||||
}
|
||||
fn floor(self) -> Self {
|
||||
unsafe { intrinsics::floorf64(self) }
|
||||
}
|
||||
fn ceil(self) -> Self {
|
||||
unsafe { intrinsics::ceilf64(self) }
|
||||
}
|
||||
fn round(self) -> Self {
|
||||
unsafe { intrinsics::roundf64(self) }
|
||||
}
|
||||
fn abs(self) -> Self {
|
||||
unsafe { intrinsics::fabsf64(self) }
|
||||
}
|
||||
fn exp(self) -> Self {
|
||||
unsafe { intrinsics::expf64(self) }
|
||||
}
|
||||
fn sqrt(self) -> Self {
|
||||
unsafe { intrinsics::sqrtf64(self) }
|
||||
}
|
||||
fn powf(self, p: Self) -> Self {
|
||||
unsafe { intrinsics::powf64(self, p) }
|
||||
}
|
||||
fn sin_cos(self) -> (Self, Self) {
|
||||
unsafe {(
|
||||
intrinsics::sinf64(self),
|
||||
intrinsics::cosf64(self),
|
||||
)}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
|
||||
#[cfg_attr(feature = "fmt", derive(Debug))]
|
||||
#[derive(Default, Copy, Clone, PartialEq, PartialOrd)]
|
||||
pub struct Finite<T>(T);
|
||||
|
||||
pub type R32 = Finite<f32>;
|
||||
pub type R64 = Finite<f64>;
|
||||
|
||||
impl<T: Real> Finite<T> {
|
||||
fn new(inner: T) -> Self {
|
||||
if !inner.is_finite() {
|
||||
Self::handle_non_finite(inner);
|
||||
}
|
||||
Self(inner)
|
||||
}
|
||||
|
||||
#[cfg(feature = "fmt")]
|
||||
fn handle_non_finite(inner: T) -> ! {
|
||||
panic!("{} is not finite", inner);
|
||||
}
|
||||
#[cfg(not(feature = "fmt"))]
|
||||
fn handle_non_finite(_inner: T) -> ! {
|
||||
panic!(); // expected a finite real
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Real> Eq for Finite<T> {}
|
||||
|
||||
impl<T: Real> Ord for Finite<T> {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.partial_cmp(other).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "fmt")]
|
||||
impl<T: fmt::Display> fmt::Display for Finite<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "fmt")]
|
||||
impl<T: fmt::LowerExp> fmt::LowerExp for Finite<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Real> Neg for Finite<T> {
|
||||
type Output = Self;
|
||||
fn neg(self) -> Self {
|
||||
Self::new(self.0.neg())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Real> AddAssign for Finite<T> {
|
||||
fn add_assign(&mut self, other: Self) {
|
||||
*self = Self::new(self.0.add(other.0))
|
||||
}
|
||||
}
|
||||
impl<T: Real> SubAssign for Finite<T> {
|
||||
fn sub_assign(&mut self, other: Self) {
|
||||
*self = Self::new(self.0.sub(other.0))
|
||||
}
|
||||
}
|
||||
impl<T: Real> MulAssign for Finite<T> {
|
||||
fn mul_assign(&mut self, other: Self) {
|
||||
*self = Self::new(self.0.mul(other.0))
|
||||
}
|
||||
}
|
||||
impl<T: Real> DivAssign for Finite<T> {
|
||||
fn div_assign(&mut self, other: Self) {
|
||||
*self = Self::new(self.0.div(other.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Real> Add for Finite<T> {
|
||||
type Output = Self;
|
||||
fn add(self, other: Self) -> Self {
|
||||
Self::new(self.0.add(other.0))
|
||||
}
|
||||
}
|
||||
impl<T: Real> Sub for Finite<T> {
|
||||
type Output = Self;
|
||||
fn sub(self, other: Self) -> Self {
|
||||
Self::new(self.0.sub(other.0))
|
||||
}
|
||||
}
|
||||
impl<T: Real> Mul for Finite<T> {
|
||||
type Output = Self;
|
||||
fn mul(self, other: Self) -> Self {
|
||||
Self::new(self.0.mul(other.0))
|
||||
}
|
||||
}
|
||||
impl<T: Real> Div for Finite<T> {
|
||||
type Output = Self;
|
||||
fn div(self, other: Self) -> Self {
|
||||
Self::new(self.0.div(other.0))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<T: ToFloat> ToFloat for Finite<T> {
|
||||
fn to_f32(&self) -> f32 {
|
||||
self.0.to_f32()
|
||||
}
|
||||
fn to_f64(&self) -> f64 {
|
||||
self.0.to_f64()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: RealFeatures> RealFeatures for Finite<T> {}
|
||||
|
||||
impl<T: Real> Real for Finite<T> {
|
||||
fn from_primitive<P: ToFloat>(p: P) -> Self {
|
||||
Self::new(T::from_primitive(p))
|
||||
}
|
||||
fn from_f32(f: f32) -> Self {
|
||||
Self::new(T::from_f32(f))
|
||||
}
|
||||
fn from_f64(f: f64) -> Self {
|
||||
Self::new(T::from_f64(f))
|
||||
}
|
||||
fn is_finite(self) -> bool {
|
||||
true
|
||||
}
|
||||
fn floor(self) -> Self {
|
||||
Self::new(self.0.floor())
|
||||
}
|
||||
fn ceil(self) -> Self {
|
||||
Self::new(self.0.ceil())
|
||||
}
|
||||
fn round(self) -> Self {
|
||||
Self::new(self.0.round())
|
||||
}
|
||||
fn abs(self) -> Self {
|
||||
Self::new(self.0.abs())
|
||||
}
|
||||
fn exp(self) -> Self {
|
||||
Self::new(self.0.exp())
|
||||
}
|
||||
fn sqrt(self) -> Self {
|
||||
Self::new(self.0.sqrt())
|
||||
}
|
||||
fn powf(self, p: Self) -> Self {
|
||||
Self::new(self.0.powf(p.0))
|
||||
}
|
||||
fn sin_cos(self) -> (Self, Self) {
|
||||
let (s, c) = self.0.sin_cos();
|
||||
(Self::new(s), Self::new(c))
|
||||
}
|
||||
|
||||
// we would ideally use `decl_consts` here, but that produces f64 -> f32 casts for R32 code.
|
||||
fn zero() -> Self {
|
||||
Self::from_primitive(T::zero())
|
||||
}
|
||||
fn one() -> Self {
|
||||
Self::from_primitive(T::one())
|
||||
}
|
||||
fn two() -> Self {
|
||||
Self::from_primitive(T::two())
|
||||
}
|
||||
fn three() -> Self {
|
||||
Self::from_primitive(T::three())
|
||||
}
|
||||
fn ten() -> Self {
|
||||
Self::from_primitive(T::ten())
|
||||
}
|
||||
fn tenth() -> Self {
|
||||
Self::from_primitive(T::tenth())
|
||||
}
|
||||
fn third() -> Self {
|
||||
Self::from_primitive(T::third())
|
||||
}
|
||||
fn half() -> Self {
|
||||
Self::from_primitive(T::half())
|
||||
}
|
||||
fn pi() -> Self {
|
||||
Self::from_primitive(T::pi())
|
||||
}
|
||||
fn two_pi() -> Self {
|
||||
Self::from_primitive(T::two_pi())
|
||||
}
|
||||
fn c() -> Self {
|
||||
Self::from_primitive(T::c())
|
||||
}
|
||||
fn eps0() -> Self {
|
||||
Self::from_primitive(T::eps0())
|
||||
}
|
||||
fn twice_eps0() -> Self {
|
||||
Self::from_primitive(T::twice_eps0())
|
||||
}
|
||||
fn mu0() -> Self {
|
||||
Self::from_primitive(T::mu0())
|
||||
}
|
||||
fn mu0_inv() -> Self {
|
||||
Self::from_primitive(T::mu0_inv())
|
||||
}
|
||||
}
|
||||
|
||||
impl ToFloat for i32 {
|
||||
fn to_f32(&self) -> f32 {
|
||||
*self as _
|
||||
}
|
||||
fn to_f64(&self) -> f64 {
|
||||
*self as _
|
||||
}
|
||||
}
|
||||
|
||||
impl ToFloat for u32 {
|
||||
fn to_f32(&self) -> f32 {
|
||||
*self as _
|
||||
}
|
||||
fn to_f64(&self) -> f64 {
|
||||
*self as _
|
||||
}
|
||||
}
|
||||
|
||||
impl ToFloat for u64 {
|
||||
fn to_f32(&self) -> f32 {
|
||||
*self as _
|
||||
}
|
||||
fn to_f64(&self) -> f64 {
|
||||
*self as _
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user