diff --git a/src/flt.rs b/src/float.rs similarity index 58% rename from src/flt.rs rename to src/float.rs index 3e51291..e9b7541 100644 --- a/src/flt.rs +++ b/src/float.rs @@ -18,26 +18,35 @@ use frac::Unsigned; use helper::FloatHelper; use {FixedI16, FixedI32, FixedI8, FixedU16, FixedU32, FixedU8}; -macro_rules! to_f { - (fn $method:ident($Uns:ty) -> $Flt:ty) => { - fn $method(self, neg: bool, frac_bits: u32) -> $Flt { - type Bits = <$Flt as FloatHelper>::Bits; - let prec = <$Flt as FloatHelper>::prec(); - let exp_min = <$Flt as FloatHelper>::exp_min(); - let exp_max = <$Flt as FloatHelper>::exp_max(); +macro_rules! from_float { + (fn $method:ident($Float:ty) -> $Uns:ty) => { + fn $method(val: $Float, frac_bits: u32) -> Option<($Uns, bool)> { + let _ = (val, frac_bits); + unimplemented!() + } + }; +} + +macro_rules! to_float { + (fn $method:ident($Uns:ty) -> $Float:ty) => { + fn $method(self, neg: bool, frac_bits: u32) -> $Float { + type FloatBits = <$Float as FloatHelper>::Bits; + let prec = <$Float as FloatHelper>::prec(); + let exp_min = <$Float as FloatHelper>::exp_min(); + let exp_max = <$Float as FloatHelper>::exp_max(); let fix_bits = mem::size_of::<$Uns>() as u32 * 8; let int_bits = fix_bits - frac_bits; let leading_zeros = self.leading_zeros(); let signif_bits = int_bits + frac_bits - leading_zeros; if signif_bits == 0 { - return <$Flt as FloatHelper>::zero(neg); + return <$Float as FloatHelper>::zero(neg); } // remove leading zeros and implicit one let mut mantissa = self << leading_zeros << 1; let exponent = int_bits as i32 - 1 - leading_zeros as i32; let biased_exponent = if exponent > exp_max { - return <$Flt as FloatHelper>::infinity(neg); + return <$Float as FloatHelper>::infinity(neg); } else if exponent < exp_min { let lost_prec = exp_min - exponent; if lost_prec as u32 >= (int_bits + frac_bits) { @@ -49,7 +58,7 @@ macro_rules! to_f { } 0 } else { - (exponent + exp_max) as Bits + (exponent + exp_max) as FloatBits }; // check for rounding let round_up = (int_bits + frac_bits >= prec) && { @@ -70,56 +79,60 @@ macro_rules! to_f { let bits_mantissa = (if int_bits + frac_bits >= prec - 1 { #[cfg_attr(feature = "cargo-clippy", allow(cast_lossless))] { - (mantissa >> (int_bits + frac_bits - (prec - 1))) as Bits + (mantissa >> (int_bits + frac_bits - (prec - 1))) as FloatBits } } else { #[cfg_attr(feature = "cargo-clippy", allow(cast_lossless))] { - (mantissa as Bits) << (prec - 1 - (int_bits + frac_bits)) + (mantissa as FloatBits) << (prec - 1 - (int_bits + frac_bits)) } }) & !(!0 << (prec - 1)); let mut bits_exp_mantissa = bits_exp | bits_mantissa; if round_up { bits_exp_mantissa += 1; } - <$Flt>::from_bits(bits_sign | bits_exp_mantissa) + <$Float>::from_bits(bits_sign | bits_exp_mantissa) } }; } -pub(crate) trait FltConv: Sized { +pub(crate) trait FloatConv: Sized { + fn from_f32(val: f32, frac_bits: u32) -> Option<(Self, bool)>; + fn from_f64(val: f64, frac_bits: u32) -> Option<(Self, bool)>; fn to_f32(self, neg: bool, frac_bits: u32) -> f32; fn to_f64(self, neg: bool, frac_bits: u32) -> f64; } -macro_rules! flt_conv { +macro_rules! float_conv { ($($Uns:ty)*) => { $( - impl FltConv for $Uns { - to_f! { fn to_f32($Uns) -> f32 } - to_f! { fn to_f64($Uns) -> f64 } + impl FloatConv for $Uns { + from_float! { fn from_f32(f32) -> $Uns } + from_float! { fn from_f64(f64) -> $Uns } + to_float! { fn to_f32($Uns) -> f32 } + to_float! { fn to_f64($Uns) -> f64 } } )* }; } -flt_conv! { u8 u16 u32 u64 u128 } +float_conv! { u8 u16 u32 u64 u128 } -macro_rules! lossless { - ($Fixed:ident:: $method:ident -> $Flt:ident) => { - impl From<$Fixed> for $Flt { +macro_rules! lossless_from_fixed { + ($Fixed:ident:: $method:ident -> $Float:ident) => { + impl From<$Fixed> for $Float { #[inline] - fn from(src: $Fixed) -> $Flt { + fn from(src: $Fixed) -> $Float { src.$method() } } }; } -lossless! { FixedI8::to_f32 -> f32 } -lossless! { FixedI16::to_f32 -> f32 } -lossless! { FixedU8::to_f32 -> f32 } -lossless! { FixedU16::to_f32 -> f32 } -lossless! { FixedI8::to_f64 -> f64 } -lossless! { FixedI16::to_f64 -> f64 } -lossless! { FixedI32::to_f64 -> f64 } -lossless! { FixedU8::to_f64 -> f64 } -lossless! { FixedU16::to_f64 -> f64 } -lossless! { FixedU32::to_f64 -> f64 } +lossless_from_fixed! { FixedI8::to_f32 -> f32 } +lossless_from_fixed! { FixedI16::to_f32 -> f32 } +lossless_from_fixed! { FixedU8::to_f32 -> f32 } +lossless_from_fixed! { FixedU16::to_f32 -> f32 } +lossless_from_fixed! { FixedI8::to_f64 -> f64 } +lossless_from_fixed! { FixedI16::to_f64 -> f64 } +lossless_from_fixed! { FixedI32::to_f64 -> f64 } +lossless_from_fixed! { FixedU8::to_f64 -> f64 } +lossless_from_fixed! { FixedU16::to_f64 -> f64 } +lossless_from_fixed! { FixedU32::to_f64 -> f64 } diff --git a/src/lib.rs b/src/lib.rs index 73a7053..b7c8927 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -138,7 +138,7 @@ macro_rules! if_unsigned { mod arith; mod cmp; mod display; -mod flt; +mod float; pub mod frac; mod helper; @@ -148,7 +148,7 @@ use core::f32; use core::f64; use core::hash::{Hash, Hasher}; use core::marker::PhantomData; -use flt::FltConv; +use float::FloatConv; use frac::Unsigned; use helper::FixedHelper; @@ -200,15 +200,41 @@ macro_rules! doc_comment_signed_unsigned { }; } -macro_rules! to_f { - (fn $method:ident(self) -> $Flt:ident) => { +macro_rules! from_float { + (fn $method:ident($Float:ident) -> $Fixed:ident < $Frac:ident >) => { doc_comment! { concat!( - "Converts the fixed-point number to `", stringify!($Flt), "`." + "Creates a fixed-point number from `", stringify!($Float), "`." ), #[inline] - pub fn $method(self) -> $Flt { - let (int_bits, frac_bits) = (Self::int_bits(), Self::frac_bits()); + pub fn $method(val: $Float) -> Option<$Fixed<$Frac>> { + let int_bits = Self::int_bits(); + let frac_bits = Self::frac_bits(); + + let (int_frac, neg) = FloatConv::$method(val, frac_bits)?; + let (int, frac) = if frac_bits == 0 { + (int_frac, 0) + } else if int_bits == 0 { + (0, int_frac) + } else { + ((int_frac >> frac_bits), (int_frac << int_bits)) + }; + Some(FixedHelper::from_parts(neg, int, frac)) + } + } + }; +} + +macro_rules! to_float { + (fn $method:ident($Fixed:ident < $Frac:ident >) -> $Float:ident) => { + doc_comment! { + concat!( + "Converts the fixed-point number to `", stringify!($Float), "`." + ), + #[inline] + pub fn $method(self) -> $Float { + let int_bits = Self::int_bits(); + let frac_bits = Self::frac_bits(); let (neg, int, frac) = self.parts(); let int_frac = if frac_bits == 0 { int @@ -217,7 +243,7 @@ macro_rules! to_f { } else { (int << frac_bits) | (frac >> int_bits) }; - FltConv::$method(int_frac, neg, frac_bits) + FloatConv::$method(int_frac, neg, frac_bits) } } }; @@ -687,8 +713,10 @@ macro_rules! fixed { } } - to_f! { fn to_f32(self) -> f32 } - to_f! { fn to_f64(self) -> f64 } + from_float! { fn from_f32(f32) -> $Fixed } + from_float! { fn from_f64(f64) -> $Fixed } + to_float! { fn to_f32($Fixed) -> f32 } + to_float! { fn to_f64($Fixed) -> f64 } pass_method! { "Returns the number of ones in the binary representation.",