add ceil and floor
[vector-math.git] / src / f16.rs
index ee13d9992135320be52859df3d5c51f6482ff933..b5d84d5a5020a12f7615e2c644a215593779167c 100644 (file)
@@ -1,8 +1,12 @@
-use core::ops::{
-    Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign,
+use crate::{
+    prim::PrimFloat,
+    scalar::Value,
+    traits::{ConvertFrom, ConvertTo, Float},
+};
+use core::{
+    fmt,
+    ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign},
 };
-
-use crate::traits::{ConvertTo, Float};
 
 #[cfg(feature = "f16")]
 use half::f16 as F16Impl;
@@ -10,10 +14,16 @@ use half::f16 as F16Impl;
 #[cfg(not(feature = "f16"))]
 type F16Impl = u16;
 
-#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
+#[derive(Clone, Copy, PartialEq, PartialOrd)]
 #[repr(transparent)]
 pub struct F16(F16Impl);
 
+#[cfg(not(feature = "f16"))]
+#[track_caller]
+pub(crate) fn panic_f16_feature_disabled() -> ! {
+    panic!("f16 feature is not enabled")
+}
+
 #[cfg(feature = "f16")]
 macro_rules! f16_impl {
     ($v:expr, [$($vars:ident),*]) => {
@@ -26,11 +36,29 @@ macro_rules! f16_impl {
     ($v:expr, [$($vars:ident),*]) => {
         {
             $(let _ = $vars;)*
-            panic!("f16 feature is not enabled")
+            panic_f16_feature_disabled()
         }
     };
 }
 
+impl fmt::Display for F16 {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f16_impl!(self.0.fmt(f), [f])
+    }
+}
+
+impl fmt::Debug for F16 {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f16_impl!(self.0.fmt(f), [f])
+    }
+}
+
+impl Default for F16 {
+    fn default() -> Self {
+        f16_impl!(F16(F16Impl::default()), [])
+    }
+}
+
 impl From<F16Impl> for F16 {
     fn from(v: F16Impl) -> Self {
         F16(v)
@@ -52,9 +80,9 @@ macro_rules! impl_f16_from {
                 }
             }
 
-            impl ConvertTo<F16> for $ty {
-                fn to(self) -> F16 {
-                    self.into()
+            impl ConvertFrom<$ty> for F16 {
+                fn cvt_from(v: $ty) -> F16 {
+                    v.into()
                 }
             }
         )*
@@ -70,9 +98,9 @@ macro_rules! impl_from_f16 {
                 }
             }
 
-            impl ConvertTo<$ty> for F16 {
-                fn to(self) -> $ty {
-                    self.into()
+            impl ConvertFrom<F16> for $ty {
+                fn cvt_from(v: F16) -> Self {
+                    v.into()
                 }
             }
         )*
@@ -86,12 +114,12 @@ impl_from_f16![f32, f64,];
 macro_rules! impl_int_to_f16 {
     ($($int:ident),*) => {
         $(
-            impl ConvertTo<F16> for $int {
-                fn to(self) -> F16 {
+            impl ConvertFrom<$int> for F16 {
+                fn cvt_from(v: $int) -> Self {
                     // f32 has enough mantissa bits such that f16 overflows to
                     // infinity before f32 stops being able to properly
                     // represent integer values, making the below conversion correct.
-                    (self as f32).to()
+                    F16::cvt_from(v as f32)
                 }
             }
         )*
@@ -101,9 +129,9 @@ macro_rules! impl_int_to_f16 {
 macro_rules! impl_f16_to_int {
     ($($int:ident),*) => {
         $(
-            impl ConvertTo<$int> for F16 {
-                fn to(self) -> $int {
-                    f32::from(self) as $int
+            impl ConvertFrom<F16> for $int {
+                fn cvt_from(v: F16) -> Self {
+                    f32::from(v) as $int
                 }
             }
         )*
@@ -113,15 +141,15 @@ macro_rules! impl_f16_to_int {
 impl_int_to_f16![i16, u16, i32, u32, i64, u64, i128, u128];
 impl_f16_to_int![i8, u8, i16, u16, i32, u32, i64, u64, i128, u128];
 
-impl ConvertTo<F16> for f32 {
-    fn to(self) -> F16 {
-        f16_impl!(F16(F16Impl::from_f32(self)), [])
+impl ConvertFrom<f32> for F16 {
+    fn cvt_from(v: f32) -> Self {
+        f16_impl!(F16(F16Impl::from_f32(v)), [v])
     }
 }
 
-impl ConvertTo<F16> for f64 {
-    fn to(self) -> F16 {
-        f16_impl!(F16(F16Impl::from_f64(self)), [])
+impl ConvertFrom<f64> for F16 {
+    fn cvt_from(v: f64) -> Self {
+        f16_impl!(F16(F16Impl::from_f64(v)), [v])
     }
 }
 
@@ -161,60 +189,107 @@ impl_bin_op_using_f32! {
     Rem, rem, RemAssign, rem_assign;
 }
 
-impl Float for F16 {
-    type FloatEncoding = F16;
-    type BitsType = u16;
-    type SignedBitsType = i16;
+impl F16 {
+    pub fn from_bits(v: u16) -> Self {
+        #[cfg(feature = "f16")]
+        return F16(F16Impl::from_bits(v));
+        #[cfg(not(feature = "f16"))]
+        return F16(v);
+    }
+    pub fn to_bits(self) -> u16 {
+        #[cfg(feature = "f16")]
+        return self.0.to_bits();
+        #[cfg(not(feature = "f16"))]
+        return self.0;
+    }
+    pub fn abs(self) -> Self {
+        f16_impl!(Self::from_bits(self.to_bits() & 0x7FFF), [])
+    }
+    pub fn copysign(self, sign: Self) -> Self {
+        f16_impl!(
+            Self::from_bits((self.to_bits() & 0x7FFF) | (sign.to_bits() & 0x8000)),
+            [sign]
+        )
+    }
+    pub fn trunc(self) -> Self {
+        return PrimFloat::trunc(f32::from(self)).to();
+    }
+    pub fn ceil(self) -> Self {
+        return PrimFloat::ceil(f32::from(self)).to();
+    }
+    pub fn floor(self) -> Self {
+        return PrimFloat::floor(f32::from(self)).to();
+    }
+    /// round to nearest, ties to unspecified
+    pub fn round(self) -> Self {
+        return PrimFloat::round(f32::from(self)).to();
+    }
+    #[cfg(feature = "fma")]
+    pub fn fma(self, a: Self, b: Self) -> Self {
+        (f64::from(self) * f64::from(a) + f64::from(b)).to()
+    }
+
+    pub fn is_nan(self) -> bool {
+        f16_impl!(self.0.is_nan(), [])
+    }
+
+    pub fn is_infinite(self) -> bool {
+        f16_impl!(self.0.is_infinite(), [])
+    }
+
+    pub fn is_finite(self) -> bool {
+        f16_impl!(self.0.is_finite(), [])
+    }
+}
+
+impl Float for Value<F16> {
+    type PrimFloat = F16;
+    type BitsType = Value<u16>;
+    type SignedBitsType = Value<i16>;
 
     fn abs(self) -> Self {
-        f16_impl!(Self::from_bits(self.to_bits() & 0x7FFF), [])
+        Value(self.0.abs())
     }
 
     fn trunc(self) -> Self {
-        f32::from(self).trunc().to()
+        Value(self.0.trunc())
     }
 
     fn ceil(self) -> Self {
-        f32::from(self).ceil().to()
+        Value(self.0.ceil())
     }
 
     fn floor(self) -> Self {
-        f32::from(self).floor().to()
+        Value(self.0.floor())
     }
 
     fn round(self) -> Self {
-        f32::from(self).round().to()
+        Value(self.0.round())
     }
 
     #[cfg(feature = "fma")]
     fn fma(self, a: Self, b: Self) -> Self {
-        (f64::from(self) * f64::from(a) + f64::from(b)).to()
+        Value(self.0.fma(a.0, b.0))
     }
 
     fn is_nan(self) -> Self::Bool {
-        f16_impl!(self.0.is_nan(), [])
+        Value(self.0.is_nan())
     }
 
     fn is_infinite(self) -> Self::Bool {
-        f16_impl!(self.0.is_infinite(), [])
+        Value(self.0.is_infinite())
     }
 
     fn is_finite(self) -> Self::Bool {
-        f16_impl!(self.0.is_finite(), [])
+        Value(self.0.is_finite())
     }
 
     fn from_bits(v: Self::BitsType) -> Self {
-        #[cfg(feature = "f16")]
-        return F16(F16Impl::from_bits(v));
-        #[cfg(not(feature = "f16"))]
-        return F16(v);
+        Value(F16::from_bits(v.0))
     }
 
     fn to_bits(self) -> Self::BitsType {
-        #[cfg(feature = "f16")]
-        return self.0.to_bits();
-        #[cfg(not(feature = "f16"))]
-        return self.0;
+        Value(self.0.to_bits())
     }
 }