eunomia 0.8.0

Atlas datatype law: the Single Source of Truth for numeric/scalar datatype vocabulary (scalars, complex, packed formats, conversions)
Documentation
use crate::types::{Bf16, Bf4, Bf8, F16, F32, F4, F64, F8};

macro_rules! impl_arithmetic {
    ($t:ident, $inner:ty, $conv_to:expr, $conv_from:expr) => {
        impl core::ops::Add for $t {
            type Output = Self;
            #[inline(always)]
            fn add(self, rhs: Self) -> Self {
                let a = $conv_to(self);
                let b = $conv_to(rhs);
                $conv_from(a + b)
            }
        }
        impl core::ops::AddAssign for $t {
            #[inline(always)]
            fn add_assign(&mut self, rhs: Self) {
                *self = *self + rhs;
            }
        }
        impl core::ops::Sub for $t {
            type Output = Self;
            #[inline(always)]
            fn sub(self, rhs: Self) -> Self {
                let a = $conv_to(self);
                let b = $conv_to(rhs);
                $conv_from(a - b)
            }
        }
        impl core::ops::SubAssign for $t {
            #[inline(always)]
            fn sub_assign(&mut self, rhs: Self) {
                *self = *self - rhs;
            }
        }
        impl core::ops::Mul for $t {
            type Output = Self;
            #[inline(always)]
            fn mul(self, rhs: Self) -> Self {
                let a = $conv_to(self);
                let b = $conv_to(rhs);
                $conv_from(a * b)
            }
        }
        impl core::ops::MulAssign for $t {
            #[inline(always)]
            fn mul_assign(&mut self, rhs: Self) {
                *self = *self * rhs;
            }
        }
        impl core::ops::Div for $t {
            type Output = Self;
            #[inline(always)]
            fn div(self, rhs: Self) -> Self {
                let a = $conv_to(self);
                let b = $conv_to(rhs);
                $conv_from(a / b)
            }
        }
        impl core::ops::Rem for $t {
            type Output = Self;
            #[inline(always)]
            fn rem(self, rhs: Self) -> Self {
                let a = $conv_to(self);
                let b = $conv_to(rhs);
                $conv_from(a % b)
            }
        }
        impl core::ops::RemAssign for $t {
            #[inline(always)]
            fn rem_assign(&mut self, rhs: Self) {
                *self = *self % rhs;
            }
        }
        impl core::ops::Neg for $t {
            type Output = Self;
            #[inline(always)]
            fn neg(self) -> Self {
                let a = $conv_to(self);
                $conv_from(-a)
            }
        }
    };
}

impl_arithmetic!(F16, u16, |x: F16| x.to_f32(), F16::from_f32);
impl_arithmetic!(F32, f32, |x: F32| x.0, F32);
impl_arithmetic!(F64, f64, |x: F64| x.0, F64);
impl_arithmetic!(Bf16, u16, |x: Bf16| x.to_f32(), Bf16::from_f32);
impl_arithmetic!(Bf8, u8, |x: Bf8| x.to_f32(), Bf8::from_f32);
impl_arithmetic!(Bf4, u8, |x: Bf4| x.to_f32(), Bf4::from_f32);
impl_arithmetic!(F8, u8, |x: F8| x.to_f32(), F8::from_f32);
impl_arithmetic!(F4, u8, |x: F4| x.to_f32(), F4::from_f32);