provide From<Fixed*> for {f32,f64} when lossless

This commit is contained in:
Trevor Spiteri 2018-08-13 19:00:36 +02:00
parent 26f760d5ca
commit 7eb5e65100
3 changed files with 109 additions and 28 deletions

View File

@ -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<Frac: Unsigned, F, Inner>(
fn fmt_radix2<Frac: Unsigned, F, UInner>(
num: F,
radix: &dyn Radix2,
fmt: &mut Formatter,
) -> FmtResult
where
F: FixedHelper<Frac, Inner = Inner>,
Inner: FmtRadix2Helper,
F: FixedHelper<Frac, UInner = UInner>,
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<Frac: Unsigned, F, Inner>(num: F, fmt: &mut Formatter) -> FmtResult
fn fmt_dec<Frac: Unsigned, F, UInner>(num: F, fmt: &mut Formatter) -> FmtResult
where
F: FixedHelper<Frac, Inner = Inner>,
Inner: FmtDecHelper,
F: FixedHelper<Frac, UInner = UInner>,
UInner: FmtDecHelper,
{
fmt_dec_helper(Frac::to_u32(), num.parts(), fmt)
}

View File

@ -14,7 +14,9 @@
// <https://opensource.org/licenses/MIT>.
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<Frac: Unsigned> From<$Fixed<Frac>> for $Flt {
#[inline]
fn from(src: $Fixed<Frac>) -> $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 }

View File

@ -114,22 +114,23 @@ float_helper! { f32(u32, 24) }
float_helper! { f64(u64, 53) }
pub(crate) trait FixedHelper<Frac: Unsigned>: Sized {
type Inner;
type UInner;
#[inline]
fn int_frac_bits() -> u32 {
mem::size_of::<Self::Inner>() as u32 * 8
mem::size_of::<Self::UInner>() as u32 * 8
}
fn one() -> Option<Self>;
fn minus_one() -> Option<Self>;
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<Frac: Unsigned> FixedHelper<Frac> for $Fixed<Frac> {
type Inner = $Inner;
type UInner = $UInner;
#[inline]
fn one() -> Option<Self> {
@ -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<Frac> {
let int_bits = <$Fixed<Frac>>::int_bits();
let frac_bits = <$Fixed<Frac>>::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<Frac>>::int_bits();
let frac_bits = <$Fixed<Frac>>::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<Frac: Unsigned> FixedHelper<Frac> for $Fixed<Frac> {
type Inner = $Inner;
type UInner = $UInner;
#[inline]
fn one() -> Option<Self> {
@ -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<Frac> {
let int_bits = <$Fixed<Frac>>::int_bits();
let frac_bits = <$Fixed<Frac>>::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<Frac>>::int_bits();
let frac_bits = <$Fixed<Frac>>::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)
}
}
};