use super::*;
pub trait Real: Num + Copy {
const PI: Self;
fn acos(self) -> Self;
fn asin(self) -> Self;
fn atan(self) -> Self;
fn atan2(y: Self, x: Self) -> Self;
fn ceil(self) -> Self;
fn cos(self) -> Self;
fn div_euclid(self, other: Self) -> Self;
fn exp(self) -> Self;
fn floor(self) -> Self;
fn fract(self) -> Self;
fn ln(self) -> Self;
fn log(self, base: Self) -> Self;
fn log10(self) -> Self;
fn log2(self) -> Self;
fn powf(self, n: Self) -> Self;
fn powi(self, n: i32) -> Self;
fn recip(self) -> Self;
fn rem_euclid(self, other: Self) -> Self;
fn round(self) -> Self;
fn sin(self) -> Self;
fn sin_cos(self) -> (Self, Self);
fn sqrt(self) -> Self;
fn tan(self) -> Self;
fn from_f32(x: f32) -> Self;
fn as_f32(self) -> f32;
}
impl<T: Real> Float for T {
const PI: Self = <Self as Real>::PI;
fn acos(self) -> Self {
Real::acos(self)
}
fn asin(self) -> Self {
Real::asin(self)
}
fn atan(self) -> Self {
Real::atan(self)
}
fn atan2(y: Self, x: Self) -> Self {
Real::atan2(y, x)
}
fn ceil(self) -> Self {
Real::ceil(self)
}
fn cos(self) -> Self {
Real::cos(self)
}
fn div_euclid(self, other: Self) -> Self {
Real::div_euclid(self, other)
}
fn exp(self) -> Self {
Real::exp(self)
}
fn floor(self) -> Self {
Real::floor(self)
}
fn fract(self) -> Self {
Real::fract(self)
}
fn ln(self) -> Self {
Real::ln(self)
}
fn log(self, base: Self) -> Self {
Real::log(self, base)
}
fn log10(self) -> Self {
Real::log10(self)
}
fn log2(self) -> Self {
Real::log2(self)
}
fn powf(self, n: Self) -> Self {
Real::powf(self, n)
}
fn powi(self, n: i32) -> Self {
Real::powi(self, n)
}
fn recip(self) -> Self {
Real::recip(self)
}
fn rem_euclid(self, other: Self) -> Self {
Real::rem_euclid(self, other)
}
fn round(self) -> Self {
Real::round(self)
}
fn sin(self) -> Self {
Real::sin(self)
}
fn sin_cos(self) -> (Self, Self) {
Real::sin_cos(self)
}
fn sqrt(self) -> Self {
Real::sqrt(self)
}
fn tan(self) -> Self {
Real::tan(self)
}
fn from_f32(x: f32) -> Self {
Real::from_f32(x)
}
fn as_f32(self) -> f32 {
Real::as_f32(self)
}
fn is_finite(self) -> bool {
true
}
}
#[derive(Copy, Clone, PartialEq, serde::Serialize)]
#[serde(transparent)]
#[repr(transparent)]
pub struct RealImpl<T: Float>(T);
macro_rules! impl_for {
($t:ty) => {
impl<'de> serde::Deserialize<'de> for RealImpl<$t> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
<$t as serde::Deserialize>::deserialize(deserializer)?
.try_into()
.map_err(serde::de::Error::custom)
}
}
impl TryFrom<$t> for RealImpl<$t> {
type Error = &'static str;
fn try_from(value: $t) -> Result<Self, Self::Error> {
if value.is_finite() {
Ok(Self::new_unchecked(value))
} else {
Err("Value must be finite")
}
}
}
};
}
#[test]
fn test_real_ron() {
let s = ron::to_string(&r32(1.5)).unwrap();
assert_eq!(ron::from_str(&s), Ok(r32(1.5)));
}
#[test]
fn test_real_bincode() {
let data = bincode::serialize(&f32::NAN).unwrap();
assert!(bincode::deserialize::<R32>(&data).is_err());
let data = bincode::serialize(&1.3f32).unwrap();
assert_eq!(bincode::deserialize::<R32>(&data).unwrap(), r32(1.3));
}
impl_for!(f32);
impl_for!(f64);
impl<T: Float> std::fmt::Debug for RealImpl<T> {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
<T as std::fmt::Debug>::fmt(&self.0, fmt)
}
}
impl<T: Float> std::fmt::Display for RealImpl<T> {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
<T as std::fmt::Display>::fmt(&self.0, fmt)
}
}
impl<T: Float> RealImpl<T> {
pub fn new(value: T) -> Self {
assert!(value.is_finite());
Self(value)
}
pub fn new_unchecked(value: T) -> Self {
Self(value)
}
pub fn raw(self) -> T {
self.0
}
}
impl<T: Float> Eq for RealImpl<T> {}
impl<T: Float> PartialOrd for RealImpl<T> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<T: Float> Ord for RealImpl<T> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.0.partial_cmp(&other.0).unwrap()
}
}
macro_rules! impl_op {
($($op:ident: $fn:ident,)*) => {
$(
impl<T: Float> std::ops::$op for RealImpl<T> {
type Output = Self;
fn $fn(self, rhs: Self) -> Self {
Self::new(self.0 .$fn(rhs.0))
}
}
)*
};
}
macro_rules! impl_op_assign {
($($op:ident: $fn:ident,)*) => {
$(
impl<T: Float> std::ops::$op for RealImpl<T> {
fn $fn(&mut self, rhs: Self) {
self.0 .$fn(rhs.0);
}
}
)*
};
}
impl_op! {
Add: add,
Sub: sub,
Mul: mul,
Div: div,
}
impl_op_assign! {
AddAssign: add_assign,
SubAssign: sub_assign,
MulAssign: mul_assign,
DivAssign: div_assign,
}
impl<T: Float> std::ops::Neg for RealImpl<T> {
type Output = Self;
fn neg(self) -> Self {
Self::new(-self.0)
}
}
impl<T: Float> UNum for RealImpl<T> {
const ZERO: Self = Self(T::ZERO);
const ONE: Self = Self(T::ONE);
}
impl<T: Float> Num for RealImpl<T> {
fn signum(self) -> Self {
Self::new(<T as Num>::signum(self.0))
}
}
pub struct UniformReal<T: rand::distributions::uniform::SampleUniform>(T::Sampler);
impl<T: Float + rand::distributions::uniform::SampleUniform>
rand::distributions::uniform::UniformSampler for UniformReal<T>
{
type X = RealImpl<T>;
fn new<B1, B2>(low: B1, high: B2) -> Self
where
B1: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
B2: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
{
Self(T::Sampler::new(low.borrow().0, high.borrow().0))
}
fn new_inclusive<B1, B2>(low: B1, high: B2) -> Self
where
B1: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
B2: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
{
Self(T::Sampler::new_inclusive(low.borrow().0, high.borrow().0))
}
fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
RealImpl(self.0.sample(rng))
}
fn sample_single<R: rand::Rng + ?Sized, B1, B2>(low: B1, high: B2, rng: &mut R) -> Self::X
where
B1: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
B2: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
{
RealImpl(T::Sampler::sample_single(
low.borrow().0,
high.borrow().0,
rng,
))
}
fn sample_single_inclusive<R: rand::Rng + ?Sized, B1, B2>(
low: B1,
high: B2,
rng: &mut R,
) -> Self::X
where
B1: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
B2: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
{
RealImpl(T::Sampler::sample_single_inclusive(
low.borrow().0,
high.borrow().0,
rng,
))
}
}
impl<T: Float + rand::distributions::uniform::SampleUniform>
rand::distributions::uniform::SampleUniform for RealImpl<T>
{
type Sampler = UniformReal<T>;
}
impl<T: Float> Real for RealImpl<T> {
const PI: Self = Self(T::PI);
fn acos(self) -> Self {
Self::new(T::acos(self.0))
}
fn asin(self) -> Self {
Self::new(T::asin(self.0))
}
fn atan(self) -> Self {
Self::new(T::atan(self.0))
}
fn atan2(y: Self, x: Self) -> Self {
Self::new(T::atan2(y.0, x.0))
}
fn ceil(self) -> Self {
Self::new(T::ceil(self.0))
}
fn cos(self) -> Self {
Self::new(T::cos(self.0))
}
fn div_euclid(self, other: Self) -> Self {
Self::new(T::div_euclid(self.0, other.0))
}
fn exp(self) -> Self {
Self::new(T::exp(self.0))
}
fn floor(self) -> Self {
Self::new(T::floor(self.0))
}
fn fract(self) -> Self {
Self::new(T::fract(self.0))
}
fn ln(self) -> Self {
Self::new(T::ln(self.0))
}
fn log(self, base: Self) -> Self {
Self::new(T::log(self.0, base.0))
}
fn log10(self) -> Self {
Self::new(T::log10(self.0))
}
fn log2(self) -> Self {
Self::new(T::log2(self.0))
}
fn powf(self, n: Self) -> Self {
Self::new(T::powf(self.0, n.0))
}
fn powi(self, n: i32) -> Self {
Self::new(T::powi(self.0, n))
}
fn recip(self) -> Self {
Self::new(T::recip(self.0))
}
fn rem_euclid(self, other: Self) -> Self {
Self::new(T::rem_euclid(self.0, other.0))
}
fn round(self) -> Self {
Self::new(T::round(self.0))
}
fn sin(self) -> Self {
Self::new(T::sin(self.0))
}
fn sin_cos(self) -> (Self, Self) {
let (sin, cos) = T::sin_cos(self.0);
(Self::new(sin), Self::new(cos))
}
fn sqrt(self) -> Self {
Self::new(T::sqrt(self.0))
}
fn tan(self) -> Self {
Self::new(T::tan(self.0))
}
fn from_f32(x: f32) -> Self {
Self::new(T::from_f32(x))
}
fn as_f32(self) -> f32 {
self.0.as_f32()
}
}
impl<T: Float> RealImpl<T> {
pub const PI: Self = <Self as Real>::PI;
pub fn acos(self) -> Self {
<Self as Real>::acos(self)
}
pub fn asin(self) -> Self {
<Self as Real>::asin(self)
}
pub fn atan(self) -> Self {
<Self as Real>::atan(self)
}
pub fn atan2(y: Self, x: Self) -> Self {
<Self as Real>::atan2(y, x)
}
pub fn ceil(self) -> Self {
<Self as Real>::ceil(self)
}
pub fn cos(self) -> Self {
<Self as Real>::cos(self)
}
pub fn div_euclid(self, other: Self) -> Self {
<Self as Real>::div_euclid(self, other)
}
pub fn exp(self) -> Self {
<Self as Real>::exp(self)
}
pub fn floor(self) -> Self {
<Self as Real>::floor(self)
}
pub fn fract(self) -> Self {
<Self as Real>::fract(self)
}
pub fn ln(self) -> Self {
<Self as Real>::ln(self)
}
pub fn log(self, base: Self) -> Self {
<Self as Real>::log(self, base)
}
pub fn log10(self) -> Self {
<Self as Real>::log10(self)
}
pub fn log2(self) -> Self {
<Self as Real>::log2(self)
}
pub fn powf(self, n: Self) -> Self {
<Self as Real>::powf(self, n)
}
pub fn powi(self, n: i32) -> Self {
<Self as Real>::powi(self, n)
}
pub fn recip(self) -> Self {
<Self as Real>::recip(self)
}
pub fn rem_euclid(self, other: Self) -> Self {
<Self as Real>::rem_euclid(self, other)
}
pub fn round(self) -> Self {
<Self as Real>::round(self)
}
pub fn signum(self) -> Self {
<Self as Num>::signum(self)
}
pub fn sin(self) -> Self {
<Self as Real>::sin(self)
}
pub fn sin_cos(self) -> (Self, Self) {
<Self as Real>::sin_cos(self)
}
pub fn sqrt(self) -> Self {
<Self as Real>::sqrt(self)
}
pub fn tan(self) -> Self {
<Self as Real>::tan(self)
}
pub fn from_f32(x: f32) -> Self {
<Self as Real>::from_f32(x)
}
pub fn as_f32(self) -> f32 {
<Self as Real>::as_f32(self)
}
}
pub type R32 = RealImpl<f32>;
pub fn r32(value: f32) -> R32 {
R32::new(value)
}
pub type R64 = RealImpl<f64>;
pub fn r64(value: f64) -> R64 {
R64::new(value)
}
#[test]
fn test_reals() {
let a = r64(3.0);
let b = r64(2.0);
println!("a = {a:?}, b = {b:?}");
println!("a + b = {:?}", a + b);
println!("a - b = {:?}", a - b);
println!("a * b = {:?}", a * b);
println!("a / b = {:?}", a / b);
println!("sin_cos(a) = {:?}", a.sin_cos());
let mut arr = [r32(1.0), r32(0.0)];
arr.sort();
let _random = rand::Rng::gen_range(&mut rand::thread_rng(), r32(0.0)..r32(1.0));
}
#[test]
#[should_panic]
fn test_reals_fail() {
println!("0 / 0 = {:?}", R64::ZERO / R64::ZERO);
}