diff --git a/src/display.rs b/src/display.rs index ad52969..308808b 100644 --- a/src/display.rs +++ b/src/display.rs @@ -21,7 +21,6 @@ use core::mem; use core::str; use frac::Unsigned; use FixedHelper; - use { FixedI128, FixedI16, FixedI32, FixedI64, FixedI8, FixedU128, FixedU16, FixedU32, FixedU64, FixedU8, @@ -74,11 +73,11 @@ trait FmtRadix2Helper { } macro_rules! fmt_radix2_helper { - ($($Inner:ty)*) => { $( - impl FmtRadix2Helper for $Inner { + ($($UInner:ty)*) => { $( + impl FmtRadix2Helper for $UInner { #[inline] fn int_frac_bits() -> u32 { - mem::size_of::<$Inner>() as u32 * 8 + mem::size_of::<$UInner>() as u32 * 8 } #[inline] @@ -96,7 +95,7 @@ macro_rules! fmt_radix2_helper { #[inline] fn take_frac_digit(&mut self, digit_bits: u32) -> u8 { - let int_frac_bits = <$Inner as FmtRadix2Helper>::int_frac_bits(); + let int_frac_bits = <$UInner as FmtRadix2Helper>::int_frac_bits(); let rem_bits = int_frac_bits - digit_bits; let mask = !0 << rem_bits; let ret = ((*self & mask) >> rem_bits) as u8; @@ -158,14 +157,14 @@ where } #[inline] -fn fmt_radix2( +fn fmt_radix2( num: F, radix: &dyn Radix2, fmt: &mut Formatter, ) -> FmtResult where - F: FixedHelper, - Inner: FmtRadix2Helper, + F: FixedHelper, + UInner: FmtRadix2Helper, { fmt_radix2_helper(Frac::to_u32(), num.parts(), radix, fmt) } @@ -272,11 +271,11 @@ trait FmtDecHelper { } macro_rules! fmt_dec_helper { - ($($Inner:ty)*) => { $( - impl FmtDecHelper for $Inner { + ($($UInner:ty)*) => { $( + impl FmtDecHelper for $UInner { #[inline] fn int_frac_bits() -> u32 { - mem::size_of::<$Inner>() as u32 * 8 + mem::size_of::<$UInner>() as u32 * 8 } #[inline] @@ -398,10 +397,10 @@ where } #[inline] -fn fmt_dec(num: F, fmt: &mut Formatter) -> FmtResult +fn fmt_dec(num: F, fmt: &mut Formatter) -> FmtResult where - F: FixedHelper, - Inner: FmtDecHelper, + F: FixedHelper, + UInner: FmtDecHelper, { fmt_dec_helper(Frac::to_u32(), num.parts(), fmt) } diff --git a/src/flt.rs b/src/flt.rs index 948a8e8..3e51291 100644 --- a/src/flt.rs +++ b/src/flt.rs @@ -14,7 +14,9 @@ // . use core::mem; +use frac::Unsigned; use helper::FloatHelper; +use {FixedI16, FixedI32, FixedI8, FixedU16, FixedU32, FixedU8}; macro_rules! to_f { (fn $method:ident($Uns:ty) -> $Flt:ty) => { @@ -99,3 +101,25 @@ macro_rules! flt_conv { )* }; } flt_conv! { u8 u16 u32 u64 u128 } + +macro_rules! lossless { + ($Fixed:ident:: $method:ident -> $Flt:ident) => { + impl From<$Fixed> for $Flt { + #[inline] + fn from(src: $Fixed) -> $Flt { + 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 } diff --git a/src/helper.rs b/src/helper.rs index dbcc68a..1164a06 100644 --- a/src/helper.rs +++ b/src/helper.rs @@ -114,22 +114,23 @@ float_helper! { f32(u32, 24) } float_helper! { f64(u64, 53) } pub(crate) trait FixedHelper: Sized { - type Inner; + type UInner; #[inline] fn int_frac_bits() -> u32 { - mem::size_of::() as u32 * 8 + mem::size_of::() as u32 * 8 } fn one() -> Option; fn minus_one() -> Option; - fn parts(self) -> (bool, Self::Inner, Self::Inner); + fn from_parts(neg: bool, int_abs: Self::UInner, frac_abs: Self::UInner) -> Self; + fn parts(self) -> (bool, Self::UInner, Self::UInner); } macro_rules! fixed_num_unsigned { - ($Fixed:ident($Inner:ty)) => { + ($Fixed:ident($UInner:ty)) => { impl FixedHelper for $Fixed { - type Inner = $Inner; + type UInner = $UInner; #[inline] fn one() -> Option { @@ -148,10 +149,33 @@ macro_rules! fixed_num_unsigned { } #[inline] - fn parts(self) -> (bool, $Inner, $Inner) { - let bits = self.to_bits(); + fn from_parts( + neg: bool, + int_abs: Self::UInner, + frac_abs: Self::UInner, + ) -> $Fixed { let int_bits = <$Fixed>::int_bits(); let frac_bits = <$Fixed>::frac_bits(); + + let _ = neg; + debug_assert!(!neg); + + let int_frac = if int_bits == 0 { + frac_abs + } else if frac_bits == 0 { + int_abs + } else { + (int_abs << frac_bits) | (frac_abs >> int_bits) + }; + $Fixed::from_bits(int_frac) + } + + #[inline] + fn parts(self) -> (bool, $UInner, $UInner) { + let int_bits = <$Fixed>::int_bits(); + let frac_bits = <$Fixed>::frac_bits(); + + let bits = self.to_bits(); let int_part = if int_bits == 0 { 0 } else { bits >> frac_bits }; let frac_part = if frac_bits == 0 { 0 } else { bits << int_bits }; (false, int_part, frac_part) @@ -161,9 +185,9 @@ macro_rules! fixed_num_unsigned { } macro_rules! fixed_num_signed { - ($Fixed:ident($Inner:ty)) => { + ($Fixed:ident($UInner:ty)) => { impl FixedHelper for $Fixed { - type Inner = $Inner; + type UInner = $UInner; #[inline] fn one() -> Option { @@ -188,13 +212,47 @@ macro_rules! fixed_num_signed { } #[inline] - fn parts(self) -> (bool, $Inner, $Inner) { - let bits = self.to_bits().wrapping_abs() as $Inner; + fn from_parts( + neg: bool, + int_abs: Self::UInner, + frac_abs: Self::UInner, + ) -> $Fixed { let int_bits = <$Fixed>::int_bits(); let frac_bits = <$Fixed>::frac_bits(); - let int_part = if int_bits == 0 { 0 } else { bits >> frac_bits }; - let frac_part = if frac_bits == 0 { 0 } else { bits << int_bits }; - (self.to_bits() < 0, int_part, frac_part) + + let int_frac_abs = if int_bits == 0 { + frac_abs + } else if frac_bits == 0 { + int_abs + } else { + (int_abs << frac_bits) | (frac_abs >> int_bits) + }; + let int_frac = if neg { + int_frac_abs.wrapping_neg() + } else { + int_frac_abs + }; + $Fixed::from_bits(int_frac as _) + } + + #[inline] + fn parts(self) -> (bool, $UInner, $UInner) { + let int_bits = <$Fixed>::int_bits(); + let frac_bits = <$Fixed>::frac_bits(); + + let (neg, abs) = if self.to_bits() < 0 { + (true, self.to_bits().wrapping_neg() as $UInner) + } else { + (false, self.to_bits() as $UInner) + }; + let (int_abs, frac_abs) = if int_bits == 0 { + (0, abs) + } else if frac_bits == 0 { + (abs, 0) + } else { + ((abs >> frac_bits), (abs << int_bits)) + }; + (neg, int_abs, frac_abs) } } };