554 lines
12 KiB
Rust
554 lines
12 KiB
Rust
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 _
|
|
}
|
|
fn to_r32(&self) -> R32 {
|
|
R32::new(self.to_f32())
|
|
}
|
|
fn to_r64(&self) -> R64 {
|
|
R64::new(self.to_f64())
|
|
}
|
|
}
|
|
|
|
|
|
#[cfg(all(not(feature = "fmt"), not(feature = "serde")))]
|
|
pub trait RealFeatures {}
|
|
|
|
#[cfg(all(not(feature = "fmt"), feature = "serde"))]
|
|
pub trait RealFeatures: Serialize + for<'a> Deserialize<'a> {}
|
|
|
|
#[cfg(all(feature = "fmt", not(feature = "serde")))]
|
|
pub trait RealFeatures: fmt::LowerExp + fmt::Display + fmt::Debug {}
|
|
|
|
#[cfg(all(feature = "fmt", feature = "serde"))]
|
|
pub trait RealFeatures: fmt::LowerExp + fmt::Display + fmt::Debug + Serialize + for<'a> Deserialize<'a> {}
|
|
|
|
/// 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 sin(self) -> Self {
|
|
self.sin_cos().0
|
|
}
|
|
fn cos(self) -> Self {
|
|
self.sin_cos().1
|
|
}
|
|
|
|
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 inv(self) -> Self {
|
|
Self::one() / self
|
|
}
|
|
|
|
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;
|
|
fn ln2() -> Self;
|
|
|
|
/// Speed of light in a vacuum; m/s.
|
|
/// Also equal to 1/sqrt(epsilon_0 mu_0)
|
|
fn c() -> Self;
|
|
fn c_inv() -> Self;
|
|
/// Vaccum Permittivity
|
|
fn eps0() -> Self;
|
|
fn eps0_inv() -> 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)
|
|
}
|
|
fn ln2() -> Self {
|
|
$wrap(0.6931471805599453)
|
|
}
|
|
|
|
/// Speed of light in a vacuum; m/s.
|
|
/// Also equal to 1/sqrt(epsilon_0 mu_0)
|
|
fn c() -> Self {
|
|
$wrap(299792458.0)
|
|
}
|
|
fn c_inv() -> Self {
|
|
$wrap(3.3356409519815204e-09)
|
|
}
|
|
/// Vaccum Permittivity
|
|
fn eps0() -> Self {
|
|
$wrap(8.854187812813e-12) // F/m
|
|
}
|
|
fn eps0_inv() -> Self {
|
|
$wrap(112940906737.1361) // m/F
|
|
}
|
|
fn twice_eps0() -> Self {
|
|
$wrap(1.7708375625626e-11) // F/m
|
|
}
|
|
/// 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))
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "iter")]
|
|
impl<T: Real> std::iter::Sum for Finite<T> {
|
|
fn sum<I>(iter: I) -> Self
|
|
where
|
|
I: Iterator<Item = Self>
|
|
{
|
|
iter.fold(Self::zero(), |a, b| a + b)
|
|
}
|
|
}
|
|
|
|
|
|
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 ln2() -> Self {
|
|
Self::from_primitive(T::ln2())
|
|
}
|
|
fn c() -> Self {
|
|
Self::from_primitive(T::c())
|
|
}
|
|
fn c_inv() -> Self {
|
|
Self::from_primitive(T::c_inv())
|
|
}
|
|
fn eps0() -> Self {
|
|
Self::from_primitive(T::eps0())
|
|
}
|
|
fn eps0_inv() -> Self {
|
|
Self::from_primitive(T::eps0_inv())
|
|
}
|
|
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 _
|
|
}
|
|
}
|