add struct ToFixedHelper

This commit is contained in:
Trevor Spiteri 2019-08-15 22:49:44 +02:00
parent aac10de995
commit 91a1f1554b
5 changed files with 99 additions and 79 deletions

View File

@ -29,16 +29,16 @@ macro_rules! fixed_cmp_fixed {
impl<FracLhs: $LhsLeEqU, FracRhs: $RhsLeEqU> PartialEq<$Rhs<FracRhs>> for $Lhs<FracLhs> {
#[inline]
fn eq(&self, rhs: &$Rhs<FracRhs>) -> bool {
let (rhs_128, dir, overflow) = rhs.to_bits().to_fixed_dir_overflow(
let conv = rhs.to_bits().to_fixed_helper(
<$Rhs<FracRhs>>::FRAC_NBITS as i32,
Self::FRAC_NBITS,
Self::INT_NBITS,
);
let rhs_bits = match rhs_128 {
let rhs_bits = match conv.bits {
Widest::Unsigned(bits) => bits as <Self as Fixed>::Bits,
Widest::Negative(bits) => bits as <Self as Fixed>::Bits,
};
dir == Ordering::Equal && !overflow && rhs_bits == self.to_bits()
conv.dir == Ordering::Equal && !conv.overflow && rhs_bits == self.to_bits()
}
}
@ -50,23 +50,23 @@ macro_rules! fixed_cmp_fixed {
(true, false) => return Some(Ordering::Less),
_ => {}
}
let (rhs_128, dir, overflow) = rhs.to_bits().to_fixed_dir_overflow(
let conv = rhs.to_bits().to_fixed_helper(
<$Rhs<FracRhs>>::FRAC_NBITS as i32,
Self::FRAC_NBITS,
Self::INT_NBITS,
);
if overflow {
if conv.overflow {
return if rhs.to_bits().is_negative() {
Some(Ordering::Greater)
} else {
Some(Ordering::Less)
};
}
let rhs_bits = match rhs_128 {
let rhs_bits = match conv.bits {
Widest::Unsigned(bits) => bits as <Self as Fixed>::Bits,
Widest::Negative(bits) => bits as <Self as Fixed>::Bits,
};
Some(self.to_bits().cmp(&rhs_bits).then(dir))
Some(self.to_bits().cmp(&rhs_bits).then(conv.dir))
}
#[inline]
@ -76,19 +76,20 @@ macro_rules! fixed_cmp_fixed {
(true, false) => return true,
_ => {}
}
let (rhs_128, dir, overflow) = rhs.to_bits().to_fixed_dir_overflow(
let conv = rhs.to_bits().to_fixed_helper(
<$Rhs<FracRhs>>::FRAC_NBITS as i32,
Self::FRAC_NBITS,
Self::INT_NBITS,
);
if overflow {
if conv.overflow {
return !rhs.to_bits().is_negative();
}
let rhs_bits = match rhs_128 {
let rhs_bits = match conv.bits {
Widest::Unsigned(bits) => bits as <Self as Fixed>::Bits,
Widest::Negative(bits) => bits as <Self as Fixed>::Bits,
};
self.to_bits() < rhs_bits || (self.to_bits() == rhs_bits && dir == Ordering::Less)
self.to_bits() < rhs_bits
|| (self.to_bits() == rhs_bits && conv.dir == Ordering::Less)
}
#[inline]
@ -189,13 +190,12 @@ macro_rules! fixed_cmp_float {
if !SealedFloat::is_finite(*rhs) {
return false;
}
let (rhs_128, dir, overflow) =
rhs.to_fixed_dir_overflow(Self::FRAC_NBITS, Self::INT_NBITS);
let rhs_bits = match rhs_128 {
let conv = rhs.to_fixed_helper(Self::FRAC_NBITS, Self::INT_NBITS);
let rhs_bits = match conv.bits {
Widest::Unsigned(bits) => bits as <Self as Fixed>::Bits,
Widest::Negative(bits) => bits as <Self as Fixed>::Bits,
};
dir == Ordering::Equal && !overflow && rhs_bits == self.to_bits()
conv.dir == Ordering::Equal && !conv.overflow && rhs_bits == self.to_bits()
}
}
@ -225,20 +225,19 @@ macro_rules! fixed_cmp_float {
(true, false) => return Some(Ordering::Less),
_ => {}
}
let (rhs_128, dir, overflow) =
rhs.to_fixed_dir_overflow(Self::FRAC_NBITS, Self::INT_NBITS);
if overflow {
let conv = rhs.to_fixed_helper(Self::FRAC_NBITS, Self::INT_NBITS);
if conv.overflow {
return if rhs_is_neg {
Some(Ordering::Greater)
} else {
Some(Ordering::Less)
};
}
let rhs_bits = match rhs_128 {
let rhs_bits = match conv.bits {
Widest::Unsigned(bits) => bits as <Self as Fixed>::Bits,
Widest::Negative(bits) => bits as <Self as Fixed>::Bits,
};
Some(self.to_bits().cmp(&rhs_bits).then(dir))
Some(self.to_bits().cmp(&rhs_bits).then(conv.dir))
}
#[inline]
@ -255,17 +254,16 @@ macro_rules! fixed_cmp_float {
(true, false) => return true,
_ => {}
}
let (rhs_128, dir, overflow) =
rhs.to_fixed_dir_overflow(Self::FRAC_NBITS, Self::INT_NBITS);
if overflow {
let conv = rhs.to_fixed_helper(Self::FRAC_NBITS, Self::INT_NBITS);
if conv.overflow {
return !rhs_is_neg;
}
let rhs_bits = match rhs_128 {
let rhs_bits = match conv.bits {
Widest::Unsigned(bits) => bits as <Self as Fixed>::Bits,
Widest::Negative(bits) => bits as <Self as Fixed>::Bits,
};
let lhs_bits = self.to_bits();
lhs_bits < rhs_bits || (lhs_bits == rhs_bits && dir == Ordering::Less)
lhs_bits < rhs_bits || (lhs_bits == rhs_bits && conv.dir == Ordering::Less)
}
#[inline]
@ -304,17 +302,16 @@ macro_rules! fixed_cmp_float {
(true, false) => return true,
_ => {}
}
let (lhs_128, dir, overflow) =
self.to_fixed_dir_overflow(<$Fix<Frac>>::FRAC_NBITS, <$Fix<Frac>>::INT_NBITS);
if overflow {
let conv = self.to_fixed_helper(<$Fix<Frac>>::FRAC_NBITS, <$Fix<Frac>>::INT_NBITS);
if conv.overflow {
return lhs_is_neg;
}
let lhs_bits = match lhs_128 {
let lhs_bits = match conv.bits {
Widest::Unsigned(bits) => bits as <$Fix<Frac> as Fixed>::Bits,
Widest::Negative(bits) => bits as <$Fix<Frac> as Fixed>::Bits,
};
let rhs_bits = rhs.to_bits();
lhs_bits < rhs_bits || (lhs_bits == rhs_bits && dir == Ordering::Greater)
lhs_bits < rhs_bits || (lhs_bits == rhs_bits && conv.dir == Ordering::Greater)
}
#[inline]

View File

@ -18,7 +18,7 @@ This module contains sealed traits.
*/
pub(crate) use crate::{
sealed_fixed::{SealedFixed, Widest},
sealed_fixed::{SealedFixed, ToFixedHelper, Widest},
sealed_float::SealedFloat,
sealed_int::SealedInt,
};

View File

@ -21,6 +21,7 @@ use crate::{
FixedU8,
};
use core::{
cmp::Ordering,
fmt::{Debug, Display},
hash::Hash,
};
@ -32,6 +33,12 @@ pub enum Widest {
Negative(i128),
}
pub struct ToFixedHelper {
pub(crate) bits: Widest,
pub(crate) dir: Ordering,
pub(crate) overflow: bool,
}
pub trait SealedFixed: Copy {
type FracNBits: Unsigned;
type SBits: SealedInt;
@ -102,12 +109,12 @@ macro_rules! sealed_fixed {
#[inline]
fn saturating_from_fixed<F: Fixed>(val: F) -> Self {
let (value, _, overflow) = val.to_sbits().to_fixed_dir_overflow(
let conv = val.to_sbits().to_fixed_helper(
F::FRAC_NBITS as i32,
Self::FRAC_NBITS,
Self::INT_NBITS,
);
if overflow {
if conv.overflow {
return if val.to_sbits().is_negative() {
SealedFixed::from_sbits(Self::SBits::min_value())
} else {
@ -116,7 +123,7 @@ macro_rules! sealed_fixed {
}
let bits = if_signed_unsigned!(
$Signedness,
match value {
match conv.bits {
Widest::Unsigned(bits) => {
if (bits as Self::SBits) < 0 {
return $Fixed::from_bits(Self::SBits::max_value());
@ -125,7 +132,7 @@ macro_rules! sealed_fixed {
}
Widest::Negative(bits) => bits as Self::SBits,
},
match value {
match conv.bits {
Widest::Unsigned(bits) => bits as Self::SBits,
Widest::Negative(_) => {
return $Fixed::from_bits(Self::SBits::min_value());
@ -137,31 +144,32 @@ macro_rules! sealed_fixed {
#[inline]
fn overflowing_from_fixed<F: Fixed>(val: F) -> (Self, bool) {
let (value, _, mut overflow) = val.to_sbits().to_fixed_dir_overflow(
let conv = val.to_sbits().to_fixed_helper(
F::FRAC_NBITS as i32,
Self::FRAC_NBITS,
Self::INT_NBITS,
);
let mut new_overflow = false;
let bits = if_signed_unsigned!(
$Signedness,
match value {
match conv.bits {
Widest::Unsigned(bits) => {
if (bits as Self::SBits) < 0 {
overflow = true;
new_overflow = true;
}
bits as Self::SBits
}
Widest::Negative(bits) => bits as Self::SBits,
},
match value {
match conv.bits {
Widest::Unsigned(bits) => bits as Self::SBits,
Widest::Negative(bits) => {
overflow = true;
new_overflow = true;
bits as Self::SBits
}
},
);
($Fixed::from_bits(bits), overflow)
($Fixed::from_bits(bits), conv.overflow || new_overflow)
}
#[inline]
@ -177,14 +185,13 @@ macro_rules! sealed_fixed {
if !val.is_finite() {
return saturated;
}
let (value, _, overflow) =
val.to_fixed_dir_overflow(Self::FRAC_NBITS, Self::INT_NBITS);
if overflow {
let conv = val.to_fixed_helper(Self::FRAC_NBITS, Self::INT_NBITS);
if conv.overflow {
return saturated;
}
let bits = if_signed_unsigned!(
$Signedness,
match value {
match conv.bits {
Widest::Unsigned(bits) => {
if (bits as Self::SBits) < 0 {
return Self::max_value();
@ -193,7 +200,7 @@ macro_rules! sealed_fixed {
}
Widest::Negative(bits) => bits as Self::SBits,
},
match value {
match conv.bits {
Widest::Unsigned(bits) => bits as Self::SBits,
Widest::Negative(_) => return Self::min_value(),
},
@ -205,28 +212,28 @@ macro_rules! sealed_fixed {
if !val.is_finite() {
panic!("{} is not finite", val.traits());
}
let (value, _, mut overflow) =
val.to_fixed_dir_overflow(Self::FRAC_NBITS, Self::INT_NBITS);
let conv = val.to_fixed_helper(Self::FRAC_NBITS, Self::INT_NBITS);
let mut new_overflow = false;
let bits = if_signed_unsigned!(
$Signedness,
match value {
match conv.bits {
Widest::Unsigned(bits) => {
if (bits as Self::SBits) < 0 {
overflow = true;
new_overflow = true;
}
bits as Self::SBits
}
Widest::Negative(bits) => bits as Self::SBits,
},
match value {
match conv.bits {
Widest::Unsigned(bits) => bits as Self::SBits,
Widest::Negative(bits) => {
overflow = true;
new_overflow = true;
bits as Self::SBits
}
},
);
($Fixed::from_bits(bits), overflow)
($Fixed::from_bits(bits), conv.overflow || new_overflow)
}
#[inline]

View File

@ -13,7 +13,7 @@
// <https://www.apache.org/licenses/LICENSE-2.0> and
// <https://opensource.org/licenses/MIT>.
use crate::sealed::{Fixed, SealedFixed, SealedInt, Widest};
use crate::sealed::{Fixed, SealedFixed, SealedInt, ToFixedHelper, Widest};
use core::{
cmp::Ordering,
fmt::{Debug, Display},
@ -79,7 +79,7 @@ pub trait SealedFloat: Copy {
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_fixed_dir_overflow(self, frac_bits: u32, int_bits: u32) -> (Widest, Ordering, bool);
fn to_fixed_helper(self, frac_bits: u32, int_bits: u32) -> ToFixedHelper;
}
macro_rules! sealed_float {
@ -212,11 +212,7 @@ macro_rules! sealed_float {
}
#[inline]
fn to_fixed_dir_overflow(
self,
dst_frac_bits: u32,
dst_int_bits: u32,
) -> (Widest, Ordering, bool) {
fn to_fixed_helper(self, dst_frac_bits: u32, dst_int_bits: u32) -> ToFixedHelper {
let prec = Self::PREC as i32;
let (neg, exp, mut mantissa) = self.parts();
@ -226,7 +222,11 @@ macro_rules! sealed_float {
mantissa |= 1 << (prec - 1);
}
if mantissa == 0 {
return (Widest::Unsigned(0), Ordering::Equal, false);
return ToFixedHelper {
bits: Widest::Unsigned(0),
dir: Ordering::Equal,
overflow: false,
};
}
let mut src_frac_bits = prec - 1 - exp;
@ -237,7 +237,11 @@ macro_rules! sealed_float {
} else {
Ordering::Less
};
return (Widest::Unsigned(0), dir, false);
return ToFixedHelper {
bits: Widest::Unsigned(0),
dir,
overflow: false,
};
}
let mut dir = Ordering::Equal;
if need_to_shr > 0 {
@ -262,9 +266,8 @@ macro_rules! sealed_float {
mantissa = -mantissa;
dir = dir.reverse();
}
let (fixed, _, overflow) =
mantissa.to_fixed_dir_overflow(src_frac_bits, dst_frac_bits, dst_int_bits);
(fixed, dir, overflow)
let conv = mantissa.to_fixed_helper(src_frac_bits, dst_frac_bits, dst_int_bits);
ToFixedHelper { dir, ..conv }
}
}
};

View File

@ -15,7 +15,7 @@
use crate::{
frac::{Bit, False, True, Unsigned, U0, U128, U16, U32, U64, U8},
sealed::{Fixed, SealedFixed, Widest},
sealed::{Fixed, SealedFixed, ToFixedHelper, Widest},
FixedI128, FixedI16, FixedI32, FixedI64, FixedI8, FixedU128, FixedU16, FixedU32, FixedU64,
FixedU8,
};
@ -94,12 +94,12 @@ pub trait SealedInt: Copy {
fn overflowing_add(self, val: Self) -> (Self, bool);
fn leading_zeros(self) -> u32;
fn to_fixed_dir_overflow(
fn to_fixed_helper(
self,
src_frac_bits: i32,
dst_frac_bits: u32,
dst_int_bits: u32,
) -> (Widest, Ordering, bool);
) -> ToFixedHelper;
fn to_repr_fixed(self) -> Self::ReprFixed;
@ -219,17 +219,21 @@ macro_rules! sealed_int {
}
#[inline]
fn to_fixed_dir_overflow(
fn to_fixed_helper(
self,
src_frac_bits: i32,
dst_frac_bits: u32,
dst_int_bits: u32,
) -> (Widest, Ordering, bool) {
) -> ToFixedHelper {
let src_bits = Self::NBITS as i32;
let dst_bits = (dst_frac_bits + dst_int_bits) as i32;
if self == 0 {
return (Widest::Unsigned(0), Ordering::Equal, false);
return ToFixedHelper {
bits:Widest::Unsigned(0),
dir:Ordering::Equal,
overflow:false,
};
}
let leading_zeros = self.leading_zeros();
@ -248,7 +252,11 @@ macro_rules! sealed_int {
_ => unreachable!(),
};
let dir = if lost_bits { Ordering::Less } else { Ordering::Equal };
(Widest::Unsigned(bits), dir, overflow)
ToFixedHelper {
bits: Widest::Unsigned(bits),
dir,
overflow,
}
}
}
};
@ -281,17 +289,21 @@ macro_rules! sealed_int {
}
#[inline]
fn to_fixed_dir_overflow(
fn to_fixed_helper(
self,
src_frac_bits: i32,
dst_frac_bits: u32,
dst_int_bits: u32,
) -> (Widest, Ordering, bool) {
) -> ToFixedHelper {
let src_bits = Self::NBITS as i32;
let dst_bits = (dst_frac_bits + dst_int_bits) as i32;
if self == 0 {
return (Widest::Unsigned(0), Ordering::Equal, false);
return ToFixedHelper {
bits: Widest::Unsigned(0),
dir: Ordering::Equal,
overflow: false,
};
}
let need_to_shr = src_frac_bits - dst_frac_bits as i32;
@ -314,11 +326,12 @@ macro_rules! sealed_int {
_ => unreachable!(),
};
let dir = if lost_bits { Ordering::Less } else { Ordering::Equal };
if self >= 0 {
(Widest::Unsigned(bits as u128), dir, overflow)
let bits = if self >= 0 {
Widest::Unsigned(bits as u128)
} else {
(Widest::Negative(bits), dir, overflow)
}
Widest::Negative(bits)
};
ToFixedHelper { bits, dir, overflow }
}
}
};