add methods to SealedInt and SealedFixed for from_int and from_fixed

This commit is contained in:
Trevor Spiteri 2019-01-28 20:44:56 +01:00
parent 073ffb0f29
commit d6775959c2
4 changed files with 89 additions and 12 deletions

View File

@ -947,7 +947,7 @@ macro_rules! fixed {
return saturated;
}
let (neg, abs_128, overflow) =
<F as SealedFloat>::to_neg_abs_overflow(val, frac_bits, int_bits);
<F as SealedFloat>::to_fixed_neg_abs_overflow(val, frac_bits, int_bits);
if overflow {
return saturated;
}
@ -1085,7 +1085,7 @@ macro_rules! fixed {
panic!("{} is not finite", val);
}
let (neg, abs_128, mut overflow) =
<F as SealedFloat>::to_neg_abs_overflow(val, frac_bits, int_bits);
<F as SealedFloat>::to_fixed_neg_abs_overflow(val, frac_bits, int_bits);
let abs_bits =
abs_128 as <<$Fixed<Frac> as SealedFixed>::Bits as SealedInt>::Unsigned;
@ -1173,14 +1173,7 @@ macro_rules! fixed {
{
let frac_bits = Self::frac_bits();
let int_bits = Self::int_bits();
let (neg, int, frac) = self.parts();
let abs = if frac_bits == 0 {
int
} else if int_bits == 0 {
frac
} else {
(int << frac_bits) | (frac >> int_bits)
};
let (neg, abs) = self.to_bits().neg_abs();
SealedFloat::from_neg_abs(neg, u128::from(abs), frac_bits, int_bits)
}
}

View File

@ -56,6 +56,8 @@ pub trait SealedFixed: Copy {
<Self::Bits as SealedInt>::Unsigned,
<Self::Bits as SealedInt>::Unsigned,
);
fn to_neg_abs_overflow(self, frac_bits: u32, int_bits: u32) -> (bool, u128, bool);
}
macro_rules! sealed_fixed {
@ -98,6 +100,38 @@ macro_rules! sealed_fixed {
};
(neg, int_abs, frac_abs)
}
#[inline]
fn to_neg_abs_overflow(
self,
dst_frac_bits: u32,
dst_int_bits: u32,
) -> (bool, u128, bool) {
let src_frac_bits = <Self as SealedFixed>::frac_bits();
let src_bits = Self::Bits::nbits() as i32;
let dst_bits = (dst_frac_bits + dst_int_bits) as i32;
if SealedInt::is_zero(self.to_bits()) {
return (false, 0, false);
}
let (neg, mut abs) = SealedInt::neg_abs(self.to_bits());
let leading_zeros = abs.leading_zeros();
abs <<= leading_zeros;
let need_to_shr =
leading_zeros as i32 + src_frac_bits as i32 - dst_frac_bits as i32;
let overflow = src_bits - need_to_shr > dst_bits;
let abs = if need_to_shr == 0 {
u128::from(abs)
} else if need_to_shr < 0 && -need_to_shr < 128 {
u128::from(abs) << -need_to_shr
} else if need_to_shr > 0 && need_to_shr < 128 {
u128::from(abs) >> need_to_shr
} else {
0
};
(neg, abs, overflow)
}
}
};
}

View File

@ -49,7 +49,7 @@ pub trait SealedFloat: Copy + Display + Debug {
fn from_neg_abs(neg: bool, abs: u128, frac_bits: u32, int_bits: u32) -> Self;
// self must be finite, otherwise meaningless results are returned
fn to_neg_abs_overflow(self, frac_bits: u32, int_bits: u32) -> (bool, u128, bool);
fn to_fixed_neg_abs_overflow(self, frac_bits: u32, int_bits: u32) -> (bool, u128, bool);
}
macro_rules! sealed_float {
@ -170,7 +170,11 @@ macro_rules! sealed_float {
Self::from_bits(bits_sign | bits_exp_mantissa)
}
fn to_neg_abs_overflow(self, frac_bits: u32, int_bits: u32) -> (bool, u128, bool) {
fn to_fixed_neg_abs_overflow(
self,
frac_bits: u32,
int_bits: u32,
) -> (bool, u128, bool) {
let float_bits = Self::Bits::nbits() as i32;
let prec = Self::prec() as i32;
let fix_bits = (frac_bits + int_bits) as i32;

View File

@ -21,6 +21,9 @@ pub trait SealedInt: Copy + Ord {
fn one_shl(shift: u32) -> Self;
fn all_ones_shl(shift: u32) -> Self;
fn is_zero(self) -> bool;
fn to_fixed_neg_abs_overflow(self, frac_bits: u32, int_bits: u32) -> (bool, u128, bool);
fn neg_abs(self) -> (bool, Self::Unsigned);
fn from_neg_abs(neg: bool, abs: Self::Unsigned) -> Self;
@ -60,6 +63,33 @@ macro_rules! sealed_int {
self == 0
}
#[inline]
fn to_fixed_neg_abs_overflow(
self,
frac_bits: u32,
int_bits: u32,
) -> (bool, u128, bool) {
let src_bits = <Self as SealedInt>::nbits() as i32;
let dst_bits = (frac_bits + int_bits) as i32;
let (neg, mut abs) = SealedInt::neg_abs(self);
let leading_zeros = abs.leading_zeros();
abs <<= leading_zeros;
let need_to_shr =
leading_zeros as i32 - frac_bits as i32;
let overflow = src_bits - need_to_shr > dst_bits;
let abs = if need_to_shr == 0 {
u128::from(abs)
} else if need_to_shr < 0 && -need_to_shr < 128 {
u128::from(abs) << -need_to_shr
} else if need_to_shr > 0 && need_to_shr < 128 {
u128::from(abs) >> need_to_shr
} else {
0
};
(neg, abs, overflow)
}
$($rest)*
}
};
@ -138,6 +168,22 @@ impl SealedInt for bool {
!self
}
#[inline]
fn to_fixed_neg_abs_overflow(self, frac_bits: u32, int_bits: u32) -> (bool, u128, bool) {
if !self {
return (false, 0, false);
}
let overflow = int_bits == 0;
let abs = if frac_bits == 0 {
1u128
} else if frac_bits < 128 {
1u128 << frac_bits
} else {
0
};
(false, abs, overflow)
}
#[inline]
fn neg_abs(self) -> (bool, bool) {
(false, self)