simplify checked conversions for floats
This commit is contained in:
parent
91a4ba3de7
commit
dad1cb298c
|
@ -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,
|
||||||
|
|
|
@ -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)
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue