simplify checked conversions for floats

This commit is contained in:
Trevor Spiteri 2019-08-03 02:06:18 +02:00
parent 91a4ba3de7
commit dad1cb298c
4 changed files with 89 additions and 109 deletions

View File

@ -215,7 +215,7 @@ use {
crate::{ crate::{
arith::MulDivDir, arith::MulDivDir,
frac::{IsLessOrEqual, True, Unsigned, U128, U16, U32, U64, U8}, frac::{IsLessOrEqual, True, Unsigned, U128, U16, U32, U64, U8},
sealed::{Fixed, Float, Int, SealedFixed, SealedFloat, SealedInt, Widest}, sealed::{Fixed, Float, Int, SealedFixed, SealedFloat, SealedInt},
}, },
core::{ core::{
cmp::Ordering, cmp::Ordering,

View File

@ -289,10 +289,7 @@ assert_eq!(Fix::from_float(",
where where
F: Float, F: Float,
{ {
let (wrapped, overflow) = Self::overflowing_from_float(val); SealedFloat::to_fixed(val)
debug_assert!(!overflow, "{} overflows", val);
let _ = overflow;
wrapped
} }
); );
@ -332,13 +329,7 @@ assert_eq!(max_fixed.to_float::<f32>(), std::f32::INFINITY);
where where
F: Float, F: Float,
{ {
let (neg, abs) = self.to_bits().neg_abs(); SealedFixed::to_float(self)
SealedFloat::from_neg_abs(
neg,
u128::from(abs),
Self::FRAC_NBITS,
Self::INT_NBITS,
)
} }
); );
@ -562,11 +553,7 @@ assert!(Fix::checked_from_float(std::f64::NAN).is_none());
where where
F: Float, F: Float,
{ {
if !val.is_finite() { SealedFloat::checked_to_fixed(val)
return None;
}
let (wrapped, overflow) = Self::overflowing_from_float(val);
if overflow { None } else { Some(wrapped) }
} }
); );
@ -799,39 +786,7 @@ assert_eq!(Fix::saturating_from_float(f64::NEG_INFINITY), Fix::min_value());
where where
F: Float, F: Float,
{ {
assert!(!val.is_nan(), "NaN"); SealedFloat::saturating_to_fixed(val)
let saturated = if val.is_sign_negative() {
Self::min_value()
} else {
Self::max_value()
};
if !val.is_finite() {
return saturated;
}
let (value, _, overflow) = val.to_fixed_dir_overflow(
Self::FRAC_NBITS,
Self::INT_NBITS,
);
if overflow {
return saturated;
}
let bits = if_signed_unsigned!(
$Signedness,
match value {
Widest::Unsigned(bits) => {
if (bits as <Self as SealedFixed>::Bits) < 0 {
return Self::max_value();
}
bits as <Self as SealedFixed>::Bits
}
Widest::Negative(bits) => bits as <Self as SealedFixed>::Bits,
},
match value {
Widest::Unsigned(bits) => bits as <Self as SealedFixed>::Bits,
Widest::Negative(_) => return Self::min_value(),
},
);
SealedFixed::from_bits(bits)
} }
); );
@ -1076,7 +1031,7 @@ assert_eq!(Fix::wrapping_from_float(large), wrapped);
where where
F: Float, F: Float,
{ {
Self::overflowing_from_float(val).0 SealedFloat::wrapping_to_fixed(val)
} }
); );
@ -1338,33 +1293,7 @@ assert_eq!(Fix::overflowing_from_float(large), (wrapped, true));
where where
F: Float, F: Float,
{ {
if !val.is_finite() { SealedFloat::overflowing_to_fixed(val)
panic!("{} is not finite", val);
}
let (value, _, mut overflow) = val.to_fixed_dir_overflow(
Self::FRAC_NBITS,
Self::INT_NBITS,
);
let bits = if_signed_unsigned!(
$Signedness,
match value {
Widest::Unsigned(bits) => {
if (bits as <Self as SealedFixed>::Bits) < 0 {
overflow = true;
}
bits as <Self as SealedFixed>::Bits
}
Widest::Negative(bits) => bits as <Self as SealedFixed>::Bits,
},
match value {
Widest::Unsigned(bits) => bits as <Self as SealedFixed>::Bits,
Widest::Negative(bits) => {
overflow = true;
bits as <Self as SealedFixed>::Bits
}
},
);
(SealedFixed::from_bits(bits), overflow)
} }
); );
}; };

View File

@ -16,7 +16,7 @@
use { use {
crate::{ crate::{
frac::{IsLessOrEqual, True, Unsigned, U128, U16, U32, U64, U8}, frac::{IsLessOrEqual, True, Unsigned, U128, U16, U32, U64, U8},
sealed::{Fixed, Float, SealedInt}, sealed::{Fixed, SealedFloat, SealedInt},
FixedI128, FixedI16, FixedI32, FixedI64, FixedI8, FixedU128, FixedU16, FixedU32, FixedU64, FixedI128, FixedI16, FixedI32, FixedI64, FixedI8, FixedU128, FixedU16, FixedU32, FixedU64,
FixedU8, FixedU8,
}, },
@ -84,12 +84,15 @@ pub trait SealedFixed: Copy + Debug + Default + Display + Eq + Hash + Ord {
where where
F: Fixed; F: Fixed;
fn saturating_from_float<F>(float: F) -> Self
where
F: SealedFloat;
fn overflowing_from_float<F>(float: F) -> (Self, bool) fn overflowing_from_float<F>(float: F) -> (Self, bool)
where where
F: Float; F: SealedFloat;
fn to_float<F>(self) -> F fn to_float<F>(self) -> F
where where
F: Float; F: SealedFloat;
#[inline] #[inline]
fn one() -> Option<Self> { fn one() -> Option<Self> {
@ -207,19 +210,83 @@ macro_rules! sealed_fixed {
} }
#[inline] #[inline]
fn overflowing_from_float<F>(float: F) -> (Self, bool) fn saturating_from_float<F>(val: F) -> Self
where where
F: Float, F: SealedFloat,
{ {
$Fixed::overflowing_from_float(float) if val.is_nan() {
panic!("NaN");
}
let saturated = if val.is_sign_negative() {
Self::min_value()
} else {
Self::max_value()
};
if !val.is_finite() {
return saturated;
}
let (value, _, overflow) =
val.to_fixed_dir_overflow(Self::FRAC_NBITS, Self::INT_NBITS);
if overflow {
return saturated;
}
let bits = if_signed_unsigned!(
$Signedness,
match value {
Widest::Unsigned(bits) => {
if (bits as <Self as SealedFixed>::Bits) < 0 {
return Self::max_value();
}
bits as <Self as SealedFixed>::Bits
}
Widest::Negative(bits) => bits as <Self as SealedFixed>::Bits,
},
match value {
Widest::Unsigned(bits) => bits as <Self as SealedFixed>::Bits,
Widest::Negative(_) => return Self::min_value(),
},
);
SealedFixed::from_bits(bits)
}
#[inline]
fn overflowing_from_float<F>(val: F) -> (Self, bool)
where
F: SealedFloat,
{
if !val.is_finite() {
panic!("{} is not finite", val);
}
let (value, _, mut overflow) =
val.to_fixed_dir_overflow(Self::FRAC_NBITS, Self::INT_NBITS);
let bits = if_signed_unsigned!(
$Signedness,
match value {
Widest::Unsigned(bits) => {
if (bits as <Self as SealedFixed>::Bits) < 0 {
overflow = true;
}
bits as <Self as SealedFixed>::Bits
}
Widest::Negative(bits) => bits as <Self as SealedFixed>::Bits,
},
match value {
Widest::Unsigned(bits) => bits as <Self as SealedFixed>::Bits,
Widest::Negative(bits) => {
overflow = true;
bits as <Self as SealedFixed>::Bits
}
},
);
(SealedFixed::from_bits(bits), overflow)
} }
#[inline] #[inline]
fn to_float<F>(self) -> F fn to_float<F>(self) -> F
where where
F: Float, F: SealedFloat,
{ {
$Fixed::to_float(self) let (neg, abs) = self.to_bits().neg_abs();
SealedFloat::from_neg_abs(neg, u128::from(abs), Self::FRAC_NBITS, Self::INT_NBITS)
} }
#[inline] #[inline]

View File

@ -64,8 +64,8 @@ pub trait SealedFloat: Copy + Debug + Display {
return None; return None;
} }
match Self::overflowing_to_fixed(self) { match Self::overflowing_to_fixed(self) {
(wrapped, false) => Some(wrapped),
(_, true) => None, (_, true) => None,
(wrapped, false) => Some(wrapped),
} }
} }
#[inline] #[inline]
@ -73,19 +73,7 @@ pub trait SealedFloat: Copy + Debug + Display {
where where
F: Fixed, F: Fixed,
{ {
assert!(!self.is_nan(), "NaN"); SealedFixed::saturating_from_float(self)
let saturated = if self.is_sign_negative() {
F::from_bits(<F as SealedFixed>::Bits::min_value())
} else {
F::from_bits(<F as SealedFixed>::Bits::max_value())
};
if !self.is_finite() {
return saturated;
}
match Self::overflowing_to_fixed(self) {
(wrapped, false) => wrapped,
(_, true) => saturated,
}
} }
#[inline] #[inline]
fn wrapping_to_fixed<F>(self) -> F fn wrapping_to_fixed<F>(self) -> F
@ -95,9 +83,13 @@ pub trait SealedFloat: Copy + Debug + Display {
let (wrapped, _) = Self::overflowing_to_fixed(self); let (wrapped, _) = Self::overflowing_to_fixed(self);
wrapped wrapped
} }
#[inline]
fn overflowing_to_fixed<F>(self) -> (F, bool) fn overflowing_to_fixed<F>(self) -> (F, bool)
where where
F: Fixed; F: Fixed,
{
SealedFixed::overflowing_from_float(self)
}
fn from_neg_abs(neg: bool, abs: u128, frac_bits: u32, int_bits: u32) -> Self; fn from_neg_abs(neg: bool, abs: u128, frac_bits: u32, int_bits: u32) -> Self;
// self must be finite, otherwise meaningless results are returned // self must be finite, otherwise meaningless results are returned
@ -171,14 +163,6 @@ macro_rules! sealed_float {
Self::from_bits(bits) Self::from_bits(bits)
} }
#[inline]
fn overflowing_to_fixed<F>(self) -> (F, bool)
where
F: Fixed,
{
F::overflowing_from_float(self)
}
#[inline] #[inline]
fn from_neg_abs(neg: bool, abs: u128, frac_bits: u32, int_bits: u32) -> $Float { fn from_neg_abs(neg: bool, abs: u128, frac_bits: u32, int_bits: u32) -> $Float {
let fix_bits = frac_bits + int_bits; let fix_bits = frac_bits + int_bits;