507 lines
12 KiB
Rust
507 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 _
|
||
}
|
||
}
|
||
|
||
|
||
#[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 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 _
|
||
}
|
||
}
|