use crate::passive::Passive;
use std::fmt::{Debug, Display};
use std::ops::{Add, Div, Mul, Neg, Sub};
pub trait Real:
Clone
+ Debug
+ Display
+ PartialEq
+ PartialOrd
+ From<f64>
+ From<i32>
+ Send
+ Sync
+ 'static
+ Neg<Output = Self>
+ Add<Self, Output = Self>
+ Sub<Self, Output = Self>
+ Mul<Self, Output = Self>
+ Div<Self, Output = Self>
{
type Passive: Passive;
fn value(&self) -> Self::Passive;
fn ln(&self) -> Self;
fn exp(&self) -> Self;
fn sqrt(&self) -> Self;
fn powf(&self, exponent: Self) -> Self;
fn powi(&self, exponent: i32) -> Self;
fn sin(&self) -> Self;
fn cos(&self) -> Self;
}
impl Real for f64 {
type Passive = f64;
#[inline]
fn value(&self) -> f64 {
*self
}
#[inline]
fn ln(&self) -> Self {
f64::ln(*self)
}
#[inline]
fn exp(&self) -> Self {
f64::exp(*self)
}
#[inline]
fn sqrt(&self) -> Self {
f64::sqrt(*self)
}
#[inline]
fn powf(&self, exponent: Self) -> Self {
f64::powf(*self, exponent)
}
#[inline]
fn powi(&self, exponent: i32) -> Self {
f64::powi(*self, exponent)
}
#[inline]
fn sin(&self) -> Self {
f64::sin(*self)
}
#[inline]
fn cos(&self) -> Self {
f64::cos(*self)
}
}
#[cfg(test)]
mod tests {
use super::*;
fn poly<R: Real>(x: &R) -> R {
x.clone() * x.clone() - R::from(3.0_f64) * x.clone() + R::from(2.0_f64)
}
#[test]
fn poly_at_three_under_f64_equals_two() {
assert_eq!(poly(&3.0_f64), 2.0);
}
#[test]
fn ln_exp_round_trips_under_f64() {
let x: f64 = 2.5;
let y = <f64 as Real>::ln(&x);
let z = <f64 as Real>::exp(&y);
assert!((z - 2.5).abs() < 1e-12);
}
#[test]
fn value_is_reflexive_on_f64() {
let x: f64 = 3.5;
assert_eq!(<f64 as Real>::value(&x), 3.5);
}
}