use std::fmt::{Debug, Display};
use std::ops::{Add, Div, Mul, Neg, Sub};
pub trait RealScalar:
Copy
+ Clone
+ Debug
+ Display
+ PartialEq
+ PartialOrd
+ Add<Output = Self>
+ Sub<Output = Self>
+ Mul<Output = Self>
+ Div<Output = Self>
+ Neg<Output = Self>
+ Send
+ Sync
+ 'static
{
fn zero() -> Self;
fn one() -> Self;
fn infinity() -> Self;
fn epsilon() -> Self;
fn literal(value: f64) -> Self;
fn to_f64(self) -> Option<f64>;
fn abs(self) -> Self;
fn sqrt(self) -> Self;
fn cbrt(self) -> Self;
fn powi(self, exponent: i32) -> Self;
fn exp(self) -> Self;
fn ln(self) -> Self;
fn cos(self) -> Self;
fn rem_euclid(self, rhs: Self) -> Self;
fn mul_add(self, multiplier: Self, addend: Self) -> Self;
fn is_finite(self) -> bool;
fn is_nan(self) -> bool;
fn total_cmp(&self, other: &Self) -> std::cmp::Ordering;
}
pub trait RandomScalar: RealScalar {
fn random_unit(rng: &mut fastrand::Rng) -> Self;
}
macro_rules! impl_native_scalar {
($type:ty, $sample:ident) => {
impl RealScalar for $type {
#[inline]
fn zero() -> Self {
0.0
}
#[inline]
fn one() -> Self {
1.0
}
#[inline]
fn infinity() -> Self {
Self::INFINITY
}
#[inline]
fn epsilon() -> Self {
Self::EPSILON
}
#[inline]
fn literal(value: f64) -> Self {
value as Self
}
#[inline]
fn to_f64(self) -> Option<f64> {
Some(self as f64)
}
#[inline]
fn abs(self) -> Self {
self.abs()
}
#[inline]
fn sqrt(self) -> Self {
self.sqrt()
}
#[inline]
fn cbrt(self) -> Self {
self.cbrt()
}
#[inline]
fn powi(self, exponent: i32) -> Self {
self.powi(exponent)
}
#[inline]
fn exp(self) -> Self {
self.exp()
}
#[inline]
fn ln(self) -> Self {
self.ln()
}
#[inline]
fn cos(self) -> Self {
self.cos()
}
#[inline]
fn rem_euclid(self, rhs: Self) -> Self {
self.rem_euclid(rhs)
}
#[inline]
fn mul_add(self, multiplier: Self, addend: Self) -> Self {
self.mul_add(multiplier, addend)
}
#[inline]
fn is_finite(self) -> bool {
self.is_finite()
}
#[inline]
fn is_nan(self) -> bool {
self.is_nan()
}
#[inline]
fn total_cmp(&self, other: &Self) -> std::cmp::Ordering {
<$type>::total_cmp(self, other)
}
}
impl RandomScalar for $type {
#[inline]
fn random_unit(rng: &mut fastrand::Rng) -> Self {
rng.$sample()
}
}
};
}
impl_native_scalar!(f64, f64);
impl_native_scalar!(f32, f32);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn literals_and_random_samples_follow_scalar_type() {
assert_eq!(f32::literal(1.25), 1.25_f32);
assert_eq!(f64::literal(1.25), 1.25_f64);
let mut rng = fastrand::Rng::with_seed(7);
assert!((0.0..1.0).contains(&f32::random_unit(&mut rng)));
assert!((0.0..1.0).contains(&f64::random_unit(&mut rng)));
}
}