use polynomen::Poly;
pub trait MulAdd<T = Self> {
type Output;
fn mul_add(self, mul: T, add: T) -> Self::Output;
}
pub trait Inv {
type Output;
fn inv(self) -> Self::Output;
}
pub trait Abs {
fn abs(&self) -> Self;
}
pub trait Const {
fn pi() -> Self;
fn tau() -> Self;
}
pub trait Zero {
fn zero() -> Self;
fn is_zero(&self) -> bool;
}
pub trait One {
fn one() -> Self;
fn is_one(&self) -> bool;
}
pub trait Cos {
fn cos(&self) -> Self;
}
pub trait Sin {
fn sin(&self) -> Self;
}
pub trait Tan {
fn tan(&self) -> Self;
}
pub trait Pow<T> {
fn powf(&self, exp: T) -> Self;
fn powi(&self, exp: i32) -> Self;
}
pub trait Exp {
fn exp(&self) -> Self;
}
pub trait Sign {
fn signum(&self) -> Self;
fn is_sign_negative(&self) -> bool;
}
pub trait Sqrt {
fn sqrt(&self) -> Self;
}
pub trait Log {
fn log10(&self) -> Self;
}
pub trait Floor {
fn floor(&self) -> Self;
}
pub trait Hypot {
fn hypot(&self, y: Self) -> Self;
}
pub trait Atan2 {
fn atan2(&self, other: Self) -> Self;
}
pub trait Infinity {
fn infinity() -> Self;
}
pub trait Degree {
fn to_degrees(self) -> Self;
}
pub trait NumCast: Sized {
fn from(n: usize) -> Option<Self>;
}
pub trait Max {
fn max(&self, other: &Self) -> Self;
}
pub trait RelativeEq {
fn relative_eq(&self, b: &Self, epsilon: &Self) -> bool;
}
macro_rules! impl_trait_float {
($t:ty, $id:ident, $z:expr, $o:expr) => {
impl MulAdd<$t> for $t {
type Output = Self;
fn mul_add(self, mul: $t, add: $t) -> Self::Output {
self.mul_add(mul, add)
}
}
impl Abs for $t {
fn abs(&self) -> Self {
<$t>::abs(*self)
}
}
impl Cos for $t {
fn cos(&self) -> Self {
<$t>::cos(*self)
}
}
impl Exp for $t {
fn exp(&self) -> Self {
<$t>::exp(*self)
}
}
impl Inv for $t {
type Output = Self;
fn inv(self) -> Self::Output {
<$t>::recip(self)
}
}
impl Log for $t {
fn log10(&self) -> Self {
<$t>::log10(*self)
}
}
impl Max for $t {
fn max(&self, other: &Self) -> Self {
<$t>::max(*self, *other)
}
}
impl Pow<$t> for $t {
fn powf(&self, exp: $t) -> Self {
<$t>::powf(*self, exp)
}
fn powi(&self, exp: i32) -> Self {
<$t>::powi(*self, exp)
}
}
impl Sign for $t {
fn signum(&self) -> Self {
<$t>::signum(*self)
}
fn is_sign_negative(&self) -> bool {
<$t>::is_sign_negative(*self)
}
}
impl Sin for $t {
fn sin(&self) -> Self {
<$t>::sin(*self)
}
}
impl Tan for $t {
fn tan(&self) -> Self {
<$t>::tan(*self)
}
}
impl Hypot for $t {
fn hypot(&self, y: Self) -> Self {
<$t>::hypot(*self, y)
}
}
impl Atan2 for $t {
fn atan2(&self, other: Self) -> Self {
<$t>::atan2(*self, other)
}
}
impl Degree for $t {
fn to_degrees(self) -> Self {
<$t>::to_degrees(self)
}
}
impl Floor for $t {
fn floor(&self) -> Self {
<$t>::floor(*self)
}
}
impl Sqrt for $t {
fn sqrt(&self) -> Self {
<$t>::sqrt(*self)
}
}
impl Infinity for $t {
fn infinity() -> Self {
std::$id::INFINITY
}
}
impl Zero for $t {
fn zero() -> Self {
$z
}
fn is_zero(&self) -> bool {
*self == $z
}
}
impl One for $t {
fn one() -> Self {
$o
}
#[allow(clippy::float_cmp)]
fn is_one(&self) -> bool {
*self == $o
}
}
impl Const for $t {
fn pi() -> Self {
std::$id::consts::PI
}
fn tau() -> Self {
std::$id::consts::TAU
}
}
impl NumCast for $t {
fn from(n: usize) -> Option<Self> {
if n == 0 {
return Some(0.);
}
let size: u32 = std::mem::size_of::<usize>() as u32 * 8;
let lz = n.leading_zeros();
let tz = n.trailing_zeros();
if size - (lz + tz) > <$t>::MANTISSA_DIGITS + 1 {
None
} else {
Some(n as $t)
}
}
}
impl RelativeEq for $t {
fn relative_eq(&self, b: &Self, epsilon: &Self) -> bool {
let a = self;
let abs_a = a.abs();
let abs_b = b.abs();
let diff = (a - b).abs();
if a == b {
true
} else if a == &0. || b == &0. || (abs_a + abs_b < <$t>::MIN_POSITIVE) {
diff < (epsilon * <$t>::MIN_POSITIVE)
} else {
diff / (abs_a + abs_b).min(<$t>::MAX) < *epsilon
}
}
}
};
}
impl_trait_float!(f32, f32, 0.0, 1.0);
impl_trait_float!(f64, f64, 0.0, 1.0);
pub trait Polynomial<T> {
fn coeffs(&self) -> Vec<T>;
fn new_from_coeffs(coeffs: &[T]) -> Self;
fn as_slice(&self) -> &[T];
}
impl<T> Polynomial<T> for Poly<T>
where
T: Clone + PartialEq + polynomen::Zero,
{
fn coeffs(&self) -> Vec<T> {
self.coeffs()
}
fn new_from_coeffs(coeffs: &[T]) -> Self {
Poly::new_from_coeffs(coeffs)
}
fn as_slice(&self) -> &[T] {
self.as_slice()
}
}
impl<T> Polynomial<T> for Vec<T>
where
T: Clone,
{
fn coeffs(&self) -> Vec<T> {
self.clone()
}
fn new_from_coeffs(coeffs: &[T]) -> Self {
Vec::from(coeffs)
}
fn as_slice(&self) -> &[T] {
self.as_slice()
}
}
impl<T> Zero for Poly<T>
where
T: PartialEq + polynomen::Zero,
{
fn zero() -> Self {
<Self as polynomen::Zero>::zero()
}
fn is_zero(&self) -> bool {
<Self as polynomen::Zero>::is_zero(self)
}
}
impl<T> One for Poly<T>
where
T: PartialEq + polynomen::One,
{
fn one() -> Self {
<Self as polynomen::One>::one()
}
fn is_one(&self) -> bool {
<Self as polynomen::One>::is_one(self)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn numeric_numcast() {
let a: f32 = NumCast::from(12).unwrap();
assert_eq!(12., a);
let a: f64 = NumCast::from(123_432).unwrap();
assert_eq!(123_432., a);
let a: Option<f32> = NumCast::from(8_000_000_001);
assert_eq!(None, a);
}
#[test]
fn numeric_numcast_f32_limit() {
let a: f32 = NumCast::from(0b1000_0000_0000_0000_0000_0000_1).unwrap();
assert_eq!(1. + 24.0_f32.exp2(), a);
let a: Option<f32> = NumCast::from(0b1000_0000_0000_0000_0000_0000_01);
assert_eq!(None, a);
}
#[test]
fn numeric_numcast_f64_limit() {
let a: f64 =
NumCast::from(0b1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_01)
.unwrap();
assert_eq!(1. + 53.0_f64.exp2(), a);
let a: Option<f64> =
NumCast::from(0b1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_001);
assert_eq!(None, a);
}
#[test]
fn polynomial_trait_for_poly() {
let p = <Poly<i32> as Polynomial<i32>>::new_from_coeffs(&[0, 1, 2]);
let c = Polynomial::<i32>::coeffs(&p);
let s = Polynomial::<i32>::as_slice(&p);
assert_eq!(s, &c);
}
#[test]
fn polynomial_trait_for_vec() {
let p = <Vec<i32> as Polynomial<i32>>::new_from_coeffs(&[0, 1, 2]);
let c = Polynomial::<i32>::coeffs(&p);
let s = Polynomial::<i32>::as_slice(&p);
assert_eq!(s, &c);
}
#[test]
fn polynomial_trait_one() {
assert!(<Poly<u8> as One>::one().is_one());
}
#[test]
fn polynomial_trait_zero() {
assert!(<Poly<u8> as Zero>::zero().is_zero());
}
}