add count_leading_zeros, count_trailing_zeros, and count_ones implementations
[vector-math.git] / src / traits.rs
index 942c67f827734139aa610d17c9ef9400e729fdf8..c02b60919cddc332266ce23b36318f2a45ec9e76 100644 (file)
+use crate::{
+    f16::F16,
+    prim::{PrimFloat, PrimSInt, PrimUInt},
+};
 use core::ops::{
     Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign,
     Mul, MulAssign, Neg, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign,
 };
 
-use crate::{f16::F16, ieee754::FloatEncoding, scalar::Scalar};
-
-#[rustfmt::skip] // work around for https://github.com/rust-lang/rustfmt/issues/4823
-macro_rules! make_float_type {
-    (
-        #[u32 = $u32:ident]
-        #[bool = $bool:ident]
-        [
-            $({
-                #[uint]
-                $uint_smaller:ident;
-                #[int]
-                $int_smaller:ident;
-                $(
-                    #[float]
-                    $float_smaller:ident;
-                )?
-            },)*
-        ],
-        {
-            #[uint]
-            $uint:ident;
-            #[int]
-            $int:ident;
-            #[float(prim = $float_prim:ident $(, scalar = $float_scalar:ident)?)]
-            $float:ident;
-        },
-        [
-            $({
-                #[uint]
-                $uint_larger:ident;
-                #[int]
-                $int_larger:ident;
-                $(
-                    #[float]
-                    $float_larger:ident;
-                )?
-            },)*
-        ]
-    ) => {
-        type $float: Float<Self::$u32, BitsType = Self::$uint, SignedBitsType = Self::$int, FloatEncoding = $float_prim>
-            $(+ From<Self::$float_scalar>)?
-            + Compare<Bool = Self::$bool>
-            + Make<Context = Self, Prim = $float_prim>
-            $(+ ConvertTo<Self::$uint_smaller>)*
-            $(+ ConvertTo<Self::$int_smaller>)*
-            $($(+ ConvertTo<Self::$float_smaller>)?)*
-            + ConvertTo<Self::$uint>
-            + ConvertTo<Self::$int>
-            $(+ ConvertTo<Self::$uint_larger>)*
-            $(+ ConvertTo<Self::$int_larger>)*
-            $($(+ Into<Self::$float_larger> + ConvertTo<Self::$float_larger>)?)*;
-    };
-    (
-        #[u32 = $u32:ident]
-        #[bool = $bool:ident]
-        [$($smaller:tt,)*],
-        {
-            #[uint]
-            $uint:ident;
-            #[int]
-            $int:ident;
-        },
-        [$($larger:tt,)*]
-    ) => {};
-}
-
-#[rustfmt::skip] // work around for https://github.com/rust-lang/rustfmt/issues/4823
-macro_rules! make_uint_int_float_type {
-    (
-        #[u32 = $u32:ident]
-        #[bool = $bool:ident]
-        [
-            $({
-                #[uint($($uint_smaller_traits:tt)*)]
-                $uint_smaller:ident;
-                #[int($($int_smaller_traits:tt)*)]
-                $int_smaller:ident;
-                $(
-                    #[float($($float_smaller_traits:tt)*)]
-                    $float_smaller:ident;
-                )?
-            },)*
-        ],
-        {
-            #[uint(prim = $uint_prim:ident $(, scalar = $uint_scalar:ident)?)]
-            $uint:ident;
-            #[int(prim = $int_prim:ident $(, scalar = $int_scalar:ident)?)]
-            $int:ident;
-            $(
-                #[float(prim = $float_prim:ident $(, scalar = $float_scalar:ident)?)]
-                $float:ident;
-            )?
-        },
-        [
-            $({
-                #[uint($($uint_larger_traits:tt)*)]
-                $uint_larger:ident;
-                #[int($($int_larger_traits:tt)*)]
-                $int_larger:ident;
-                $(
-                    #[float($($float_larger_traits:tt)*)]
-                    $float_larger:ident;
-                )?
-            },)*
-        ]
-    ) => {
-        type $uint: UInt<Self::$u32>
-            $(+ From<Self::$uint_scalar>)?
-            + Compare<Bool = Self::$bool>
-            + Make<Context = Self, Prim = $uint_prim>
-            $(+ ConvertTo<Self::$uint_smaller>)*
-            $(+ ConvertTo<Self::$int_smaller>)*
-            $($(+ ConvertTo<Self::$float_smaller>)?)*
-            + ConvertTo<Self::$int>
-            $(+ ConvertTo<Self::$float>)?
-            $(+ Into<Self::$uint_larger> + ConvertTo<Self::$uint_larger>)*
-            $(+ Into<Self::$int_larger> + ConvertTo<Self::$int_larger>)*
-            $($(+ Into<Self::$float_larger> + ConvertTo<Self::$float_larger>)?)*;
-        type $int: SInt<Self::$u32>
-            $(+ From<Self::$int_scalar>)?
-            + Compare<Bool = Self::$bool>
-            + Make<Context = Self, Prim = $int_prim>
-            $(+ ConvertTo<Self::$uint_smaller>)*
-            $(+ ConvertTo<Self::$int_smaller>)*
-            $($(+ ConvertTo<Self::$float_smaller>)?)*
-            + ConvertTo<Self::$uint>
-            $(+ ConvertTo<Self::$float>)?
-            $(+ ConvertTo<Self::$uint_larger>)*
-            $(+ Into<Self::$int_larger> + ConvertTo<Self::$int_larger>)*
-            $($(+ Into<Self::$float_larger> + ConvertTo<Self::$float_larger>)?)*;
-        make_float_type! {
-            #[u32 = $u32]
-            #[bool = $bool]
-            [
-                $({
-                    #[uint]
-                    $uint_smaller;
-                    #[int]
-                    $int_smaller;
-                    $(
-                        #[float]
-                        $float_smaller;
-                    )?
-                },)*
-            ],
-            {
-                #[uint]
-                $uint;
-                #[int]
-                $int;
-                $(
-                    #[float(prim = $float_prim $(, scalar = $float_scalar)?)]
-                    $float;
-                )?
-            },
-            [
-                $({
-                    #[uint]
-                    $uint_larger;
-                    #[int]
-                    $int_larger;
-                    $(
-                        #[float]
-                        $float_larger;
-                    )?
-                },)*
-            ]
-        }
-    };
-}
-
-macro_rules! make_uint_int_float_types {
-    (
-        #[u32 = $u32:ident]
-        #[bool = $bool:ident]
-        [$($smaller:tt,)*],
-        $current:tt,
-        [$first_larger:tt, $($larger:tt,)*]
-    ) => {
-        make_uint_int_float_type! {
-            #[u32 = $u32]
-            #[bool = $bool]
-            [$($smaller,)*],
-            $current,
-            [$first_larger, $($larger,)*]
-        }
-        make_uint_int_float_types! {
-            #[u32 = $u32]
-            #[bool = $bool]
-            [$($smaller,)* $current,],
-            $first_larger,
-            [$($larger,)*]
-        }
-    };
-    (
-        #[u32 = $u32:ident]
-        #[bool = $bool:ident]
-        [$($smaller:tt,)*],
-        $current:tt,
-        []
-    ) => {
-        make_uint_int_float_type! {
-            #[u32 = $u32]
-            #[bool = $bool]
-            [$($smaller,)*],
-            $current,
-            []
-        }
-    };
-}
-
-#[rustfmt::skip] // work around for https://github.com/rust-lang/rustfmt/issues/4823
-macro_rules! make_types {
-    (
-        #[bool]
-        $(#[scalar = $ScalarBool:ident])?
-        type $Bool:ident;
-
-        #[u8]
-        $(#[scalar = $ScalarU8:ident])?
-        type $U8:ident;
-
-        #[u16]
-        $(#[scalar = $ScalarU16:ident])?
-        type $U16:ident;
-
-        #[u32]
-        $(#[scalar = $ScalarU32:ident])?
-        type $U32:ident;
-
-        #[u64]
-        $(#[scalar = $ScalarU64:ident])?
-        type $U64:ident;
-
-        #[i8]
-        $(#[scalar = $ScalarI8:ident])?
-        type $I8:ident;
-
-        #[i16]
-        $(#[scalar = $ScalarI16:ident])?
-        type $I16:ident;
-
-        #[i32]
-        $(#[scalar = $ScalarI32:ident])?
-        type $I32:ident;
-
-        #[i64]
-        $(#[scalar = $ScalarI64:ident])?
-        type $I64:ident;
-
-        #[f16]
-        $(#[scalar = $ScalarF16:ident])?
-        type $F16:ident;
-
-        #[f32]
-        $(#[scalar = $ScalarF32:ident])?
-        type $F32:ident;
-
-        #[f64]
-        $(#[scalar = $ScalarF64:ident])?
-        type $F64:ident;
-    ) => {
-        type $Bool: Bool
-            $(+ From<Self::$ScalarBool>)?
-            + Make<Context = Self, Prim = bool>
-            + Select<Self::$Bool>
-            + Select<Self::$U8>
-            + Select<Self::$U16>
-            + Select<Self::$U32>
-            + Select<Self::$U64>
-            + Select<Self::$I8>
-            + Select<Self::$I16>
-            + Select<Self::$I32>
-            + Select<Self::$I64>
-            + Select<Self::$F16>
-            + Select<Self::$F32>
-            + Select<Self::$F64>;
-        make_uint_int_float_types! {
-            #[u32 = $U32]
-            #[bool = $Bool]
-            [],
-            {
-                #[uint(prim = u8 $(, scalar = $ScalarU8)?)]
-                $U8;
-                #[int(prim = i8 $(, scalar = $ScalarI8)?)]
-                $I8;
-            },
-            [
-                {
-                    #[uint(prim = u16 $(, scalar = $ScalarU16)?)]
-                    $U16;
-                    #[int(prim = i16 $(, scalar = $ScalarI16)?)]
-                    $I16;
-                    #[float(prim = F16 $(, scalar = $ScalarF16)?)]
-                    $F16;
-                },
-                {
-                    #[uint(prim = u32 $(, scalar = $ScalarU32)?)]
-                    $U32;
-                    #[int(prim = i32 $(, scalar = $ScalarI32)?)]
-                    $I32;
-                    #[float(prim = f32 $(, scalar = $ScalarF32)?)]
-                    $F32;
-                },
-                {
-                    #[uint(prim = u64 $(, scalar = $ScalarU64)?)]
-                    $U64;
-                    #[int(prim = i64 $(, scalar = $ScalarI64)?)]
-                    $I64;
-                    #[float(prim = f64 $(, scalar = $ScalarF64)?)]
-                    $F64;
-                },
-            ]
-        }
-    };
-}
-
 /// reference used to build IR for Kazan; an empty type for `core::simd`
 pub trait Context: Copy {
-    make_types! {
-        #[bool]
-        type Bool;
-
-        #[u8]
-        type U8;
-
-        #[u16]
-        type U16;
-
-        #[u32]
-        type U32;
-
-        #[u64]
-        type U64;
-
-        #[i8]
-        type I8;
-
-        #[i16]
-        type I16;
-
-        #[i32]
-        type I32;
-
-        #[i64]
-        type I64;
-
-        #[f16]
-        type F16;
-
-        #[f32]
-        type F32;
-
-        #[f64]
-        type F64;
-    }
-    make_types! {
-        #[bool]
-        #[scalar = Bool]
-        type VecBool;
-
-        #[u8]
-        #[scalar = U8]
-        type VecU8;
-
-        #[u16]
-        #[scalar = U16]
-        type VecU16;
-
-        #[u32]
-        #[scalar = U32]
-        type VecU32;
-
-        #[u64]
-        #[scalar = U64]
-        type VecU64;
-
-        #[i8]
-        #[scalar = I8]
-        type VecI8;
-
-        #[i16]
-        #[scalar = I16]
-        type VecI16;
-
-        #[i32]
-        #[scalar = I32]
-        type VecI32;
-
-        #[i64]
-        #[scalar = I64]
-        type VecI64;
-
-        #[f16]
-        #[scalar = F16]
-        type VecF16;
-
-        #[f32]
-        #[scalar = F32]
-        type VecF32;
-
-        #[f64]
-        #[scalar = F64]
-        type VecF64;
-    }
+    vector_math_proc_macro::make_context_types!();
     fn make<T: Make<Context = Self>>(self, v: T::Prim) -> T {
         T::make(self, v)
     }
@@ -421,37 +22,47 @@ pub trait Make: Copy {
     fn make(ctx: Self::Context, v: Self::Prim) -> Self;
 }
 
+pub trait ConvertFrom<T>: Sized {
+    fn cvt_from(v: T) -> Self;
+}
+
+impl<T> ConvertFrom<T> for T {
+    fn cvt_from(v: T) -> Self {
+        v
+    }
+}
+
 pub trait ConvertTo<T> {
     fn to(self) -> T;
 }
 
-macro_rules! impl_convert_to_using_as {
-    ($($src:ident -> [$($dest:ident),*];)*) => {
-        $($(
-            impl ConvertTo<$dest> for $src {
-                fn to(self) -> $dest {
-                    self as $dest
+impl<F, T: ConvertFrom<F>> ConvertTo<T> for F {
+    fn to(self) -> T {
+        T::cvt_from(self)
+    }
+}
+
+macro_rules! impl_convert_from_using_as {
+    ($first:ident $(, $ty:ident)*) => {
+        $(
+            impl ConvertFrom<$first> for $ty {
+                fn cvt_from(v: $first) -> Self {
+                    v as _
                 }
             }
-        )*)*
-    };
-    ([$($src:ident),*] -> $dest:tt;) => {
-        impl_convert_to_using_as! {
-            $(
-                $src -> $dest;
-            )*
-        }
+            impl ConvertFrom<$ty> for $first {
+                fn cvt_from(v: $ty) -> Self {
+                    v as _
+                }
+            }
+        )*
+        impl_convert_from_using_as![$($ty),*];
     };
-    ([$($src:ident),*];) => {
-        impl_convert_to_using_as! {
-            [$($src),*] -> [$($src),*];
-        }
+    () => {
     };
 }
 
-impl_convert_to_using_as! {
-    [u8, i8, u16, i16, u32, i32, u64, i64, f32, f64];
-}
+impl_convert_from_using_as![u8, i8, u16, i16, u32, i32, u64, i64, f32, f64];
 
 pub trait Number:
     Compare
@@ -507,13 +118,8 @@ impl<T> BitOps for T where
 {
 }
 
-pub trait Int<ShiftRhs>:
-    Number
-    + BitOps
-    + Shl<ShiftRhs, Output = Self>
-    + Shr<ShiftRhs, Output = Self>
-    + ShlAssign<ShiftRhs>
-    + ShrAssign<ShiftRhs>
+pub trait Int:
+    Number + BitOps + Shl<Output = Self> + Shr<Output = Self> + ShlAssign + ShrAssign
 {
     fn leading_zeros(self) -> Self;
     fn leading_ones(self) -> Self {
@@ -529,76 +135,61 @@ pub trait Int<ShiftRhs>:
     fn count_ones(self) -> Self;
 }
 
-pub trait UInt<ShiftRhs>: Int<ShiftRhs> {}
-
-pub trait SInt<ShiftRhs>: Int<ShiftRhs> + Neg<Output = Self> {}
-
-macro_rules! impl_int {
-    ($ty:ident) => {
-        impl Int<u32> for $ty {
-            fn leading_zeros(self) -> Self {
-                self.leading_zeros() as Self
-            }
-            fn leading_ones(self) -> Self {
-                self.leading_ones() as Self
-            }
-            fn trailing_zeros(self) -> Self {
-                self.trailing_zeros() as Self
-            }
-            fn trailing_ones(self) -> Self {
-                self.trailing_ones() as Self
-            }
-            fn count_zeros(self) -> Self {
-                self.count_zeros() as Self
-            }
-            fn count_ones(self) -> Self {
-                self.count_ones() as Self
-            }
-        }
-    };
-}
-
-macro_rules! impl_uint {
-    ($($ty:ident),*) => {
-        $(
-            impl_int!($ty);
-            impl UInt<u32> for $ty {}
-        )*
-    };
+pub trait UInt: Int + Make<Prim = Self::PrimUInt> + ConvertFrom<Self::SignedType> {
+    type PrimUInt: PrimUInt<SignedType = <Self::SignedType as SInt>::PrimSInt>;
+    type SignedType: SInt
+        + ConvertFrom<Self>
+        + Make<Context = Self::Context>
+        + Compare<Bool = Self::Bool>;
 }
 
-impl_uint![u8, u16, u32, u64];
-
-macro_rules! impl_sint {
-    ($($ty:ident),*) => {
-        $(
-            impl_int!($ty);
-            impl SInt<u32> for $ty {}
-        )*
-    };
+pub trait SInt:
+    Int + Neg<Output = Self> + Make<Prim = Self::PrimSInt> + ConvertFrom<Self::UnsignedType>
+{
+    type PrimSInt: PrimSInt<UnsignedType = <Self::UnsignedType as UInt>::PrimUInt>;
+    type UnsignedType: UInt
+        + ConvertFrom<Self>
+        + Make<Context = Self::Context>
+        + Compare<Bool = Self::Bool>;
 }
 
-impl_sint![i8, i16, i32, i64];
-
-pub trait Float<BitsShiftRhs: Make<Context = Self::Context, Prim = u32>>:
-    Number + Neg<Output = Self>
+pub trait Float:
+    Number
+    + Neg<Output = Self>
+    + Make<Prim = Self::PrimFloat>
+    + ConvertFrom<Self::SignedBitsType>
+    + ConvertFrom<Self::BitsType>
 {
-    type FloatEncoding: FloatEncoding + Make<Context = Scalar, Prim = <Self as Make>::Prim>;
-    type BitsType: UInt<BitsShiftRhs>
-        + Make<Context = Self::Context, Prim = <Self::FloatEncoding as Float<u32>>::BitsType>
-        + ConvertTo<Self::SignedBitsType>
-        + Compare<Bool = Self::Bool>;
-    type SignedBitsType: SInt<BitsShiftRhs>
-        + Make<Context = Self::Context, Prim = <Self::FloatEncoding as Float<u32>>::SignedBitsType>
-        + ConvertTo<Self::BitsType>
-        + Compare<Bool = Self::Bool>;
+    type PrimFloat: PrimFloat;
+    type BitsType: UInt<PrimUInt = <Self::PrimFloat as PrimFloat>::BitsType, SignedType = Self::SignedBitsType>
+        + Make<Context = Self::Context, Prim = <Self::PrimFloat as PrimFloat>::BitsType>
+        + Compare<Bool = Self::Bool>
+        + ConvertFrom<Self>;
+    type SignedBitsType: SInt<
+            PrimSInt = <Self::PrimFloat as PrimFloat>::SignedBitsType,
+            UnsignedType = Self::BitsType,
+        > + Make<Context = Self::Context, Prim = <Self::PrimFloat as PrimFloat>::SignedBitsType>
+        + Compare<Bool = Self::Bool>
+        + ConvertFrom<Self>;
     fn abs(self) -> Self;
+    fn copy_sign(self, sign: Self) -> Self {
+        crate::algorithms::base::copy_sign(self.ctx(), self, sign)
+    }
     fn trunc(self) -> Self;
     fn ceil(self) -> Self;
     fn floor(self) -> Self;
+    /// round to nearest integer, unspecified which way half-way cases are rounded
     fn round(self) -> Self;
+    /// returns `self * a + b` but only rounding once
     #[cfg(feature = "fma")]
     fn fma(self, a: Self, b: Self) -> Self;
+    /// returns `self * a + b` either using `fma` or `self * a + b`
+    fn mul_add_fast(self, a: Self, b: Self) -> Self {
+        #[cfg(feature = "fma")]
+        return self.fma(a, b);
+        #[cfg(not(feature = "fma"))]
+        return self * a + b;
+    }
     fn is_nan(self) -> Self::Bool {
         self.ne(self)
     }
@@ -606,127 +197,76 @@ pub trait Float<BitsShiftRhs: Make<Context = Self::Context, Prim = u32>>:
         self.abs().eq(Self::infinity(self.ctx()))
     }
     fn infinity(ctx: Self::Context) -> Self {
-        Self::from_bits(ctx.make(Self::FloatEncoding::INFINITY_BITS))
+        Self::from_bits(ctx.make(Self::PrimFloat::INFINITY_BITS))
     }
     fn nan(ctx: Self::Context) -> Self {
-        Self::from_bits(ctx.make(Self::FloatEncoding::NAN_BITS))
+        Self::from_bits(ctx.make(Self::PrimFloat::NAN_BITS))
     }
     fn is_finite(self) -> Self::Bool;
     fn is_zero_or_subnormal(self) -> Self::Bool {
-        self.extract_exponent_field().eq(self
-            .ctx()
-            .make(Self::FloatEncoding::ZERO_SUBNORMAL_EXPONENT))
+        self.extract_exponent_field()
+            .eq(self.ctx().make(Self::PrimFloat::ZERO_SUBNORMAL_EXPONENT))
     }
     fn from_bits(v: Self::BitsType) -> Self;
     fn to_bits(self) -> Self::BitsType;
     fn extract_exponent_field(self) -> Self::BitsType {
-        let mask = self.ctx().make(Self::FloatEncoding::EXPONENT_FIELD_MASK);
-        let shift = self.ctx().make(Self::FloatEncoding::EXPONENT_FIELD_SHIFT);
+        let mask = self.ctx().make(Self::PrimFloat::EXPONENT_FIELD_MASK);
+        let shift = self.ctx().make(Self::PrimFloat::EXPONENT_FIELD_SHIFT);
         (self.to_bits() & mask) >> shift
     }
     fn extract_exponent_unbiased(self) -> Self::SignedBitsType {
         Self::sub_exponent_bias(self.extract_exponent_field())
     }
     fn extract_mantissa_field(self) -> Self::BitsType {
-        let mask = self.ctx().make(Self::FloatEncoding::MANTISSA_FIELD_MASK);
+        let mask = self.ctx().make(Self::PrimFloat::MANTISSA_FIELD_MASK);
         self.to_bits() & mask
     }
+    fn is_sign_negative(self) -> Self::Bool {
+        let mask = self.ctx().make(Self::PrimFloat::SIGN_FIELD_MASK);
+        self.ctx()
+            .make::<Self::BitsType>(0.to())
+            .ne(self.to_bits() & mask)
+    }
+    fn is_sign_positive(self) -> Self::Bool {
+        let mask = self.ctx().make(Self::PrimFloat::SIGN_FIELD_MASK);
+        self.ctx()
+            .make::<Self::BitsType>(0.to())
+            .eq(self.to_bits() & mask)
+    }
+    fn extract_sign_field(self) -> Self::BitsType {
+        let shift = self.ctx().make(Self::PrimFloat::SIGN_FIELD_SHIFT);
+        self.to_bits() >> shift
+    }
+    fn from_fields(
+        sign_field: Self::BitsType,
+        exponent_field: Self::BitsType,
+        mantissa_field: Self::BitsType,
+    ) -> Self {
+        let sign_shift = sign_field.ctx().make(Self::PrimFloat::SIGN_FIELD_SHIFT);
+        let exponent_shift = sign_field.ctx().make(Self::PrimFloat::EXPONENT_FIELD_SHIFT);
+        Self::from_bits(
+            (sign_field << sign_shift) | (exponent_field << exponent_shift) | mantissa_field,
+        )
+    }
     fn sub_exponent_bias(exponent_field: Self::BitsType) -> Self::SignedBitsType {
-        exponent_field.to()
+        Self::SignedBitsType::cvt_from(exponent_field)
             - exponent_field
                 .ctx()
-                .make(Self::FloatEncoding::EXPONENT_BIAS_SIGNED)
+                .make(Self::PrimFloat::EXPONENT_BIAS_SIGNED)
     }
     fn add_exponent_bias(exponent: Self::SignedBitsType) -> Self::BitsType {
-        (exponent
-            + exponent
-                .ctx()
-                .make(Self::FloatEncoding::EXPONENT_BIAS_SIGNED))
-        .to()
+        (exponent + exponent.ctx().make(Self::PrimFloat::EXPONENT_BIAS_SIGNED)).to()
     }
 }
 
-macro_rules! impl_float {
-    ($ty:ty, $bits:ty, $signed_bits:ty) => {
-        impl Float<u32> for $ty {
-            type FloatEncoding = $ty;
-            type BitsType = $bits;
-            type SignedBitsType = $signed_bits;
-            fn abs(self) -> Self {
-                #[cfg(feature = "std")]
-                return self.abs();
-                #[cfg(not(feature = "std"))]
-                todo!();
-            }
-            fn trunc(self) -> Self {
-                #[cfg(feature = "std")]
-                return self.trunc();
-                #[cfg(not(feature = "std"))]
-                todo!();
-            }
-            fn ceil(self) -> Self {
-                #[cfg(feature = "std")]
-                return self.ceil();
-                #[cfg(not(feature = "std"))]
-                todo!();
-            }
-            fn floor(self) -> Self {
-                #[cfg(feature = "std")]
-                return self.floor();
-                #[cfg(not(feature = "std"))]
-                todo!();
-            }
-            fn round(self) -> Self {
-                #[cfg(feature = "std")]
-                return self.round();
-                #[cfg(not(feature = "std"))]
-                todo!();
-            }
-            #[cfg(feature = "fma")]
-            fn fma(self, a: Self, b: Self) -> Self {
-                self.mul_add(a, b)
-            }
-            fn is_nan(self) -> Self::Bool {
-                self.is_nan()
-            }
-            fn is_infinite(self) -> Self::Bool {
-                self.is_infinite()
-            }
-            fn is_finite(self) -> Self::Bool {
-                self.is_finite()
-            }
-            fn from_bits(v: Self::BitsType) -> Self {
-                <$ty>::from_bits(v)
-            }
-            fn to_bits(self) -> Self::BitsType {
-                self.to_bits()
-            }
-        }
-    };
-}
-
-impl_float!(f32, u32, i32);
-impl_float!(f64, u64, i64);
-
-pub trait Bool: Make + BitOps {}
+pub trait Bool: Make<Prim = bool> + BitOps + Select<Self> {}
 
-impl Bool for bool {}
-
-pub trait Select<T>: Bool {
+pub trait Select<T> {
     fn select(self, true_v: T, false_v: T) -> T;
 }
 
-impl<T> Select<T> for bool {
-    fn select(self, true_v: T, false_v: T) -> T {
-        if self {
-            true_v
-        } else {
-            false_v
-        }
-    }
-}
 pub trait Compare: Make {
-    type Bool: Bool + Select<Self>;
+    type Bool: Bool + Select<Self> + Make<Context = Self::Context>;
     fn eq(self, rhs: Self) -> Self::Bool;
     fn ne(self, rhs: Self) -> Self::Bool;
     fn lt(self, rhs: Self) -> Self::Bool;
@@ -734,33 +274,3 @@ pub trait Compare: Make {
     fn le(self, rhs: Self) -> Self::Bool;
     fn ge(self, rhs: Self) -> Self::Bool;
 }
-
-macro_rules! impl_compare_using_partial_cmp {
-    ($($ty:ty),*) => {
-        $(
-            impl Compare for $ty {
-                type Bool = bool;
-                fn eq(self, rhs: Self) -> Self::Bool {
-                    self == rhs
-                }
-                fn ne(self, rhs: Self) -> Self::Bool {
-                    self != rhs
-                }
-                fn lt(self, rhs: Self) -> Self::Bool {
-                    self < rhs
-                }
-                fn gt(self, rhs: Self) -> Self::Bool {
-                    self > rhs
-                }
-                fn le(self, rhs: Self) -> Self::Bool {
-                    self <= rhs
-                }
-                fn ge(self, rhs: Self) -> Self::Bool {
-                    self >= rhs
-                }
-            }
-        )*
-    };
-}
-
-impl_compare_using_partial_cmp![u8, i8, u16, i16, F16, u32, i32, f32, u64, i64, f64];