move float conversions to convert.rs
This commit is contained in:
parent
b71b41cd70
commit
ef902eb60e
277
src/convert.rs
277
src/convert.rs
|
@ -249,6 +249,36 @@ fixed_to_prim! { (FixedU64, FixedI64) -> wider (u128, i128) }
|
||||||
|
|
||||||
fixed_to_prim! { (FixedU128, FixedI128) -> (u128, i128) }
|
fixed_to_prim! { (FixedU128, FixedI128) -> (u128, i128) }
|
||||||
|
|
||||||
|
macro_rules! fixed_to_float {
|
||||||
|
($Fixed:ident($Len:ty):: $method:ident -> $Float:ident) => {
|
||||||
|
impl<Frac> From<$Fixed<Frac>> for $Float
|
||||||
|
where
|
||||||
|
Frac: Unsigned + IsLessOrEqual<$Len, Output = True>,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn from(src: $Fixed<Frac>) -> $Float {
|
||||||
|
src.$method()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "f16")]
|
||||||
|
fixed_to_float! { FixedI8(U8)::to_f16 -> f16 }
|
||||||
|
#[cfg(feature = "f16")]
|
||||||
|
fixed_to_float! { FixedU8(U8)::to_f16 -> f16 }
|
||||||
|
fixed_to_float! { FixedI8(U8)::to_f32 -> f32 }
|
||||||
|
fixed_to_float! { FixedI16(U16)::to_f32 -> f32 }
|
||||||
|
fixed_to_float! { FixedU8(U8)::to_f32 -> f32 }
|
||||||
|
fixed_to_float! { FixedU16(U16)::to_f32 -> f32 }
|
||||||
|
fixed_to_float! { FixedI8(U8)::to_f64 -> f64 }
|
||||||
|
fixed_to_float! { FixedI16(U16)::to_f64 -> f64 }
|
||||||
|
fixed_to_float! { FixedI32(U32)::to_f64 -> f64 }
|
||||||
|
fixed_to_float! { FixedU8(U8)::to_f64 -> f64 }
|
||||||
|
fixed_to_float! { FixedU16(U16)::to_f64 -> f64 }
|
||||||
|
fixed_to_float! { FixedU32(U32)::to_f64 -> f64 }
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "cargo-clippy", allow(clippy::float_cmp))]
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use *;
|
use *;
|
||||||
|
@ -357,4 +387,251 @@ mod tests {
|
||||||
assert_eq!(HH128::from(h), HH128::from_bits(val128 << 119));
|
assert_eq!(HH128::from(h), HH128::from_bits(val128 << 119));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn signed_from_f32() {
|
||||||
|
type Fix = FixedI8<frac::U4>;
|
||||||
|
// 1.1 -> 0001.1000
|
||||||
|
assert_eq!(Fix::from_f32(3.0 / 2.0).unwrap(), Fix::from_bits(24));
|
||||||
|
// 0.11 -> 0000.1100
|
||||||
|
assert_eq!(Fix::from_f32(3.0 / 4.0).unwrap(), Fix::from_bits(12));
|
||||||
|
// 0.011 -> 0000.0110
|
||||||
|
assert_eq!(Fix::from_f32(3.0 / 8.0).unwrap(), Fix::from_bits(6));
|
||||||
|
// 0.0011 -> 0000.0011
|
||||||
|
assert_eq!(Fix::from_f32(3.0 / 16.0).unwrap(), Fix::from_bits(3));
|
||||||
|
// 0.00011 -> 0000.0010 (tie to even)
|
||||||
|
assert_eq!(Fix::from_f32(3.0 / 32.0).unwrap(), Fix::from_bits(2));
|
||||||
|
// 0.00101 -> 0000.0010 (tie to even)
|
||||||
|
assert_eq!(Fix::from_f32(5.0 / 32.0).unwrap(), Fix::from_bits(2));
|
||||||
|
// 0.000011 -> 0000.0001 (nearest)
|
||||||
|
assert_eq!(Fix::from_f32(3.0 / 64.0).unwrap(), Fix::from_bits(1));
|
||||||
|
// 0.00001 -> 0000.0000 (tie to even)
|
||||||
|
assert_eq!(Fix::from_f32(1.0 / 32.0).unwrap(), Fix::from_bits(0));
|
||||||
|
|
||||||
|
// -1.1 -> -0001.1000
|
||||||
|
assert_eq!(Fix::from_f32(-3.0 / 2.0).unwrap(), Fix::from_bits(-24));
|
||||||
|
// -0.11 -> -0000.1100
|
||||||
|
assert_eq!(Fix::from_f32(-3.0 / 4.0).unwrap(), Fix::from_bits(-12));
|
||||||
|
// -0.011 -> -0000.0110
|
||||||
|
assert_eq!(Fix::from_f32(-3.0 / 8.0).unwrap(), Fix::from_bits(-6));
|
||||||
|
// -0.0011 -> -0000.0011
|
||||||
|
assert_eq!(Fix::from_f32(-3.0 / 16.0).unwrap(), Fix::from_bits(-3));
|
||||||
|
// -0.00011 -> -0000.0010 (tie to even)
|
||||||
|
assert_eq!(Fix::from_f32(-3.0 / 32.0).unwrap(), Fix::from_bits(-2));
|
||||||
|
// -0.00101 -> -0000.0010 (tie to even)
|
||||||
|
assert_eq!(Fix::from_f32(-5.0 / 32.0).unwrap(), Fix::from_bits(-2));
|
||||||
|
// -0.000011 -> -0000.0001 (nearest)
|
||||||
|
assert_eq!(Fix::from_f32(-3.0 / 64.0).unwrap(), Fix::from_bits(-1));
|
||||||
|
// -0.00001 -> 0000.0000 (tie to even)
|
||||||
|
assert_eq!(Fix::from_f32(-1.0 / 32.0).unwrap(), Fix::from_bits(0));
|
||||||
|
|
||||||
|
// 111.1111 -> 111.1111
|
||||||
|
assert_eq!(Fix::from_f32(127.0 / 16.0).unwrap(), Fix::from_bits(127));
|
||||||
|
// 111.11111 -> too large (tie to even)
|
||||||
|
assert!(Fix::from_f32(255.0 / 32.0).is_none());
|
||||||
|
|
||||||
|
// -111.1111 -> -111.1111
|
||||||
|
assert_eq!(Fix::from_f32(-127.0 / 16.0).unwrap(), Fix::from_bits(-127));
|
||||||
|
// -111.11111 -> -1000.0000 (tie to even)
|
||||||
|
assert_eq!(Fix::from_f32(-255.0 / 32.0).unwrap(), Fix::from_bits(-128));
|
||||||
|
// -1000.00001 -> -1000.0000 (tie to even)
|
||||||
|
assert_eq!(Fix::from_f32(-257.0 / 32.0).unwrap(), Fix::from_bits(-128));
|
||||||
|
// -1000.0001 -> too small
|
||||||
|
assert!(Fix::from_f32(-129.0 / 16.0).is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unsigned_from_f32() {
|
||||||
|
type Fix = FixedU8<frac::U4>;
|
||||||
|
// 1.1 -> 0001.1000
|
||||||
|
assert_eq!(Fix::from_f32(3.0 / 2.0).unwrap(), Fix::from_bits(24));
|
||||||
|
// 0.11 -> 0000.1100
|
||||||
|
assert_eq!(Fix::from_f32(3.0 / 4.0).unwrap(), Fix::from_bits(12));
|
||||||
|
// 0.011 -> 0000.0110
|
||||||
|
assert_eq!(Fix::from_f32(3.0 / 8.0).unwrap(), Fix::from_bits(6));
|
||||||
|
// 0.0011 -> 0000.0011
|
||||||
|
assert_eq!(Fix::from_f32(3.0 / 16.0).unwrap(), Fix::from_bits(3));
|
||||||
|
// 0.00011 -> 0000.0010 (tie to even)
|
||||||
|
assert_eq!(Fix::from_f32(3.0 / 32.0).unwrap(), Fix::from_bits(2));
|
||||||
|
// 0.00101 -> 0000.0010 (tie to even)
|
||||||
|
assert_eq!(Fix::from_f32(5.0 / 32.0).unwrap(), Fix::from_bits(2));
|
||||||
|
// 0.000011 -> 0000.0001 (nearest)
|
||||||
|
assert_eq!(Fix::from_f32(3.0 / 64.0).unwrap(), Fix::from_bits(1));
|
||||||
|
// 0.00001 -> 0000.0000 (tie to even)
|
||||||
|
assert_eq!(Fix::from_f32(1.0 / 32.0).unwrap(), Fix::from_bits(0));
|
||||||
|
// -0.00001 -> 0000.0000 (tie to even)
|
||||||
|
assert_eq!(Fix::from_f32(-1.0 / 32.0).unwrap(), Fix::from_bits(0));
|
||||||
|
// -0.0001 -> too small
|
||||||
|
assert!(Fix::from_f32(-1.0 / 16.0).is_none());
|
||||||
|
|
||||||
|
// 1111.1111 -> 1111.1111
|
||||||
|
assert_eq!(Fix::from_f32(255.0 / 16.0).unwrap(), Fix::from_bits(255));
|
||||||
|
// 1111.11111 -> too large (tie to even)
|
||||||
|
assert!(Fix::from_f32(511.0 / 32.0).is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "f16")]
|
||||||
|
#[test]
|
||||||
|
fn to_f16() {
|
||||||
|
use half::f16;
|
||||||
|
for u in 0x00..=0xff {
|
||||||
|
let fu = FixedU8::<frac::U7>::from_bits(u);
|
||||||
|
assert_eq!(fu.to_f16(), f16::from_f32(u as f32 / 128.0));
|
||||||
|
let i = u as i8;
|
||||||
|
let fi = FixedI8::<frac::U7>::from_bits(i);
|
||||||
|
assert_eq!(fi.to_f16(), f16::from_f32(i as f32 / 128.0));
|
||||||
|
|
||||||
|
for hi in &[
|
||||||
|
0u32,
|
||||||
|
0x0000_0100,
|
||||||
|
0x7fff_ff00,
|
||||||
|
0x8000_0000,
|
||||||
|
0x8100_0000,
|
||||||
|
0xffff_fe00,
|
||||||
|
0xffff_ff00,
|
||||||
|
] {
|
||||||
|
let uu = *hi | u as u32;
|
||||||
|
let fuu = FixedU32::<frac::U7>::from_bits(uu);
|
||||||
|
assert_eq!(fuu.to_f16(), f16::from_f32(uu as f32 / 128.0));
|
||||||
|
let ii = uu as i32;
|
||||||
|
let fii = FixedI32::<frac::U7>::from_bits(ii);
|
||||||
|
assert_eq!(fii.to_f16(), f16::from_f32(ii as f32 / 128.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
for hi in &[
|
||||||
|
0u128,
|
||||||
|
0x0000_0000_0000_0000_0000_0000_0000_0100,
|
||||||
|
0x7fff_ffff_ffff_ffff_ffff_ffff_ffff_ff00,
|
||||||
|
0x8000_0000_0000_0000_0000_0000_0000_0000,
|
||||||
|
0x8100_0000_0000_0000_0000_0000_0000_0000,
|
||||||
|
0xffff_ffff_ffff_ffff_ffff_ffff_ffff_fe00,
|
||||||
|
0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ff00,
|
||||||
|
] {
|
||||||
|
let uu = *hi | u as u128;
|
||||||
|
let fuu = FixedU128::<frac::U7>::from_bits(uu);
|
||||||
|
assert_eq!(fuu.to_f16(), f16::from_f64(uu as f64 / 128.0));
|
||||||
|
let ii = uu as i128;
|
||||||
|
let fii = FixedI128::<frac::U7>::from_bits(ii);
|
||||||
|
assert_eq!(fii.to_f16(), f16::from_f64(ii as f64 / 128.0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn to_f32() {
|
||||||
|
for u in 0x00..=0xff {
|
||||||
|
let fu = FixedU8::<frac::U7>::from_bits(u);
|
||||||
|
assert_eq!(fu.to_f32(), f32::from(u) / 128.0);
|
||||||
|
let i = u as i8;
|
||||||
|
let fi = FixedI8::<frac::U7>::from_bits(i);
|
||||||
|
assert_eq!(fi.to_f32(), f32::from(i) / 128.0);
|
||||||
|
|
||||||
|
for hi in &[
|
||||||
|
0u32,
|
||||||
|
0x0000_0100,
|
||||||
|
0x7fff_ff00,
|
||||||
|
0x8000_0000,
|
||||||
|
0x8100_0000,
|
||||||
|
0xffff_fe00,
|
||||||
|
0xffff_ff00,
|
||||||
|
] {
|
||||||
|
let uu = *hi | u32::from(u);
|
||||||
|
let fuu = FixedU32::<frac::U7>::from_bits(uu);
|
||||||
|
assert_eq!(fuu.to_f32(), uu as f32 / 128.0);
|
||||||
|
let ii = uu as i32;
|
||||||
|
let fii = FixedI32::<frac::U7>::from_bits(ii);
|
||||||
|
assert_eq!(fii.to_f32(), ii as f32 / 128.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for hi in &[
|
||||||
|
0u128,
|
||||||
|
0x0000_0000_0000_0000_0000_0000_0000_0100,
|
||||||
|
0x7fff_ffff_ffff_ffff_ffff_ffff_ffff_ff00,
|
||||||
|
0x8000_0000_0000_0000_0000_0000_0000_0000,
|
||||||
|
0x8100_0000_0000_0000_0000_0000_0000_0000,
|
||||||
|
0xffff_ffff_ffff_ffff_ffff_ffff_ffff_fe00,
|
||||||
|
0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ff00,
|
||||||
|
] {
|
||||||
|
let uu = *hi | u128::from(u);
|
||||||
|
let fuu = FixedU128::<frac::U7>::from_bits(uu);
|
||||||
|
assert_eq!(fuu.to_f32(), (uu as f64 / 128.0) as f32);
|
||||||
|
let ii = uu as i128;
|
||||||
|
let fii = FixedI128::<frac::U7>::from_bits(ii);
|
||||||
|
assert_eq!(fii.to_f32(), (ii as f64 / 128.0) as f32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn to_infinite_f32() {
|
||||||
|
// too_large is 1.ffff_ffff_ffff... << 127,
|
||||||
|
// which will be rounded to 1.0 << 128.
|
||||||
|
let too_large = FixedU128::<frac::U0>::max_value();
|
||||||
|
assert_eq!(too_large.count_ones(), 128);
|
||||||
|
assert!(too_large.to_f32().is_infinite());
|
||||||
|
|
||||||
|
// still_too_large is 1.ffff_ff << 127,
|
||||||
|
// which is exactly midway between 1.0 << 128 (even)
|
||||||
|
// and the largest normal f32 that is 1.ffff_fe << 127 (odd).
|
||||||
|
// The tie will be rounded to even, which is to 1.0 << 128.
|
||||||
|
let still_too_large = too_large << 103u32;
|
||||||
|
assert_eq!(still_too_large.count_ones(), 25);
|
||||||
|
assert!(still_too_large.to_f32().is_infinite());
|
||||||
|
|
||||||
|
// not_too_large is 1.ffff_feff_ffff... << 127,
|
||||||
|
// which will be rounded to 1.ffff_fe << 127.
|
||||||
|
let not_too_large = still_too_large - FixedU128::from_bits(1);
|
||||||
|
assert_eq!(not_too_large.count_ones(), 127);
|
||||||
|
assert!(!not_too_large.to_f32().is_infinite());
|
||||||
|
|
||||||
|
// min_128 is -1.0 << 127.
|
||||||
|
let min_i128 = FixedI128::<frac::U0>::min_value();
|
||||||
|
assert_eq!(min_i128.count_ones(), 1);
|
||||||
|
assert_eq!(min_i128.to_f32(), -(127f32.exp2()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn to_f64() {
|
||||||
|
for u in 0x00..=0xff {
|
||||||
|
let fu = FixedU8::<frac::U7>::from_bits(u);
|
||||||
|
assert_eq!(fu.to_f32(), f32::from(u) / 128.0);
|
||||||
|
let i = u as i8;
|
||||||
|
let fi = FixedI8::<frac::U7>::from_bits(i);
|
||||||
|
assert_eq!(fi.to_f32(), f32::from(i) / 128.0);
|
||||||
|
|
||||||
|
for hi in &[
|
||||||
|
0u64,
|
||||||
|
0x0000_0000_0000_0100,
|
||||||
|
0x7fff_ffff_ffff_ff00,
|
||||||
|
0x8000_0000_0000_0000,
|
||||||
|
0x8100_0000_0000_0000,
|
||||||
|
0xffff_ffff_ffff_fe00,
|
||||||
|
0xffff_ffff_ffff_ff00,
|
||||||
|
] {
|
||||||
|
let uu = *hi | u64::from(u);
|
||||||
|
let fuu = FixedU64::<frac::U7>::from_bits(uu);
|
||||||
|
assert_eq!(fuu.to_f64(), uu as f64 / 128.0);
|
||||||
|
let ii = uu as i64;
|
||||||
|
let fii = FixedI64::<frac::U7>::from_bits(ii);
|
||||||
|
assert_eq!(fii.to_f64(), ii as f64 / 128.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for hi in &[
|
||||||
|
0u128,
|
||||||
|
0x0000_0000_0000_0000_0000_0000_0000_0100,
|
||||||
|
0x7fff_ffff_ffff_ffff_ffff_ffff_ffff_ff00,
|
||||||
|
0x8000_0000_0000_0000_0000_0000_0000_0000,
|
||||||
|
0x8100_0000_0000_0000_0000_0000_0000_0000,
|
||||||
|
0xffff_ffff_ffff_ffff_ffff_ffff_ffff_fe00,
|
||||||
|
0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ff00,
|
||||||
|
] {
|
||||||
|
let uu = *hi | u128::from(u);
|
||||||
|
let fuu = FixedU128::<frac::U7>::from_bits(uu);
|
||||||
|
assert_eq!(fuu.to_f64(), uu as f64 / 128.0);
|
||||||
|
let ii = uu as i128;
|
||||||
|
let fii = FixedI128::<frac::U7>::from_bits(ii);
|
||||||
|
assert_eq!(fii.to_f64(), ii as f64 / 128.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
284
src/float.rs
284
src/float.rs
|
@ -14,11 +14,9 @@
|
||||||
// <https://opensource.org/licenses/MIT>.
|
// <https://opensource.org/licenses/MIT>.
|
||||||
|
|
||||||
use core::mem;
|
use core::mem;
|
||||||
use frac::{IsLessOrEqual, True, Unsigned, U16, U32, U8};
|
|
||||||
#[cfg(feature = "f16")]
|
#[cfg(feature = "f16")]
|
||||||
use half::f16;
|
use half::f16;
|
||||||
use helper::FloatHelper;
|
use helper::FloatHelper;
|
||||||
use {FixedI16, FixedI32, FixedI8, FixedU16, FixedU32, FixedU8};
|
|
||||||
|
|
||||||
macro_rules! from_float {
|
macro_rules! from_float {
|
||||||
(fn $method:ident($Float:ty) -> $Uns:ty) => {
|
(fn $method:ident($Float:ty) -> $Uns:ty) => {
|
||||||
|
@ -176,285 +174,3 @@ macro_rules! float_conv {
|
||||||
)* };
|
)* };
|
||||||
}
|
}
|
||||||
float_conv! { u8 u16 u32 u64 u128 }
|
float_conv! { u8 u16 u32 u64 u128 }
|
||||||
|
|
||||||
macro_rules! lossless_from_fixed {
|
|
||||||
($Fixed:ident($Len:ty):: $method:ident -> $Float:ident) => {
|
|
||||||
impl<Frac> From<$Fixed<Frac>> for $Float
|
|
||||||
where
|
|
||||||
Frac: Unsigned + IsLessOrEqual<$Len, Output = True>,
|
|
||||||
{
|
|
||||||
#[inline]
|
|
||||||
fn from(src: $Fixed<Frac>) -> $Float {
|
|
||||||
src.$method()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "f16")]
|
|
||||||
lossless_from_fixed! { FixedI8(U8)::to_f16 -> f16 }
|
|
||||||
#[cfg(feature = "f16")]
|
|
||||||
lossless_from_fixed! { FixedU8(U8)::to_f16 -> f16 }
|
|
||||||
lossless_from_fixed! { FixedI8(U8)::to_f32 -> f32 }
|
|
||||||
lossless_from_fixed! { FixedI16(U16)::to_f32 -> f32 }
|
|
||||||
lossless_from_fixed! { FixedU8(U8)::to_f32 -> f32 }
|
|
||||||
lossless_from_fixed! { FixedU16(U16)::to_f32 -> f32 }
|
|
||||||
lossless_from_fixed! { FixedI8(U8)::to_f64 -> f64 }
|
|
||||||
lossless_from_fixed! { FixedI16(U16)::to_f64 -> f64 }
|
|
||||||
lossless_from_fixed! { FixedI32(U32)::to_f64 -> f64 }
|
|
||||||
lossless_from_fixed! { FixedU8(U8)::to_f64 -> f64 }
|
|
||||||
lossless_from_fixed! { FixedU16(U16)::to_f64 -> f64 }
|
|
||||||
lossless_from_fixed! { FixedU32(U32)::to_f64 -> f64 }
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "cargo-clippy", allow(clippy::float_cmp))]
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use *;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn signed_from_f32() {
|
|
||||||
type Fix = FixedI8<frac::U4>;
|
|
||||||
// 1.1 -> 0001.1000
|
|
||||||
assert_eq!(Fix::from_f32(3.0 / 2.0).unwrap(), Fix::from_bits(24));
|
|
||||||
// 0.11 -> 0000.1100
|
|
||||||
assert_eq!(Fix::from_f32(3.0 / 4.0).unwrap(), Fix::from_bits(12));
|
|
||||||
// 0.011 -> 0000.0110
|
|
||||||
assert_eq!(Fix::from_f32(3.0 / 8.0).unwrap(), Fix::from_bits(6));
|
|
||||||
// 0.0011 -> 0000.0011
|
|
||||||
assert_eq!(Fix::from_f32(3.0 / 16.0).unwrap(), Fix::from_bits(3));
|
|
||||||
// 0.00011 -> 0000.0010 (tie to even)
|
|
||||||
assert_eq!(Fix::from_f32(3.0 / 32.0).unwrap(), Fix::from_bits(2));
|
|
||||||
// 0.00101 -> 0000.0010 (tie to even)
|
|
||||||
assert_eq!(Fix::from_f32(5.0 / 32.0).unwrap(), Fix::from_bits(2));
|
|
||||||
// 0.000011 -> 0000.0001 (nearest)
|
|
||||||
assert_eq!(Fix::from_f32(3.0 / 64.0).unwrap(), Fix::from_bits(1));
|
|
||||||
// 0.00001 -> 0000.0000 (tie to even)
|
|
||||||
assert_eq!(Fix::from_f32(1.0 / 32.0).unwrap(), Fix::from_bits(0));
|
|
||||||
|
|
||||||
// -1.1 -> -0001.1000
|
|
||||||
assert_eq!(Fix::from_f32(-3.0 / 2.0).unwrap(), Fix::from_bits(-24));
|
|
||||||
// -0.11 -> -0000.1100
|
|
||||||
assert_eq!(Fix::from_f32(-3.0 / 4.0).unwrap(), Fix::from_bits(-12));
|
|
||||||
// -0.011 -> -0000.0110
|
|
||||||
assert_eq!(Fix::from_f32(-3.0 / 8.0).unwrap(), Fix::from_bits(-6));
|
|
||||||
// -0.0011 -> -0000.0011
|
|
||||||
assert_eq!(Fix::from_f32(-3.0 / 16.0).unwrap(), Fix::from_bits(-3));
|
|
||||||
// -0.00011 -> -0000.0010 (tie to even)
|
|
||||||
assert_eq!(Fix::from_f32(-3.0 / 32.0).unwrap(), Fix::from_bits(-2));
|
|
||||||
// -0.00101 -> -0000.0010 (tie to even)
|
|
||||||
assert_eq!(Fix::from_f32(-5.0 / 32.0).unwrap(), Fix::from_bits(-2));
|
|
||||||
// -0.000011 -> -0000.0001 (nearest)
|
|
||||||
assert_eq!(Fix::from_f32(-3.0 / 64.0).unwrap(), Fix::from_bits(-1));
|
|
||||||
// -0.00001 -> 0000.0000 (tie to even)
|
|
||||||
assert_eq!(Fix::from_f32(-1.0 / 32.0).unwrap(), Fix::from_bits(0));
|
|
||||||
|
|
||||||
// 111.1111 -> 111.1111
|
|
||||||
assert_eq!(Fix::from_f32(127.0 / 16.0).unwrap(), Fix::from_bits(127));
|
|
||||||
// 111.11111 -> too large (tie to even)
|
|
||||||
assert!(Fix::from_f32(255.0 / 32.0).is_none());
|
|
||||||
|
|
||||||
// -111.1111 -> -111.1111
|
|
||||||
assert_eq!(Fix::from_f32(-127.0 / 16.0).unwrap(), Fix::from_bits(-127));
|
|
||||||
// -111.11111 -> -1000.0000 (tie to even)
|
|
||||||
assert_eq!(Fix::from_f32(-255.0 / 32.0).unwrap(), Fix::from_bits(-128));
|
|
||||||
// -1000.00001 -> -1000.0000 (tie to even)
|
|
||||||
assert_eq!(Fix::from_f32(-257.0 / 32.0).unwrap(), Fix::from_bits(-128));
|
|
||||||
// -1000.0001 -> too small
|
|
||||||
assert!(Fix::from_f32(-129.0 / 16.0).is_none());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn unsigned_from_f32() {
|
|
||||||
type Fix = FixedU8<frac::U4>;
|
|
||||||
// 1.1 -> 0001.1000
|
|
||||||
assert_eq!(Fix::from_f32(3.0 / 2.0).unwrap(), Fix::from_bits(24));
|
|
||||||
// 0.11 -> 0000.1100
|
|
||||||
assert_eq!(Fix::from_f32(3.0 / 4.0).unwrap(), Fix::from_bits(12));
|
|
||||||
// 0.011 -> 0000.0110
|
|
||||||
assert_eq!(Fix::from_f32(3.0 / 8.0).unwrap(), Fix::from_bits(6));
|
|
||||||
// 0.0011 -> 0000.0011
|
|
||||||
assert_eq!(Fix::from_f32(3.0 / 16.0).unwrap(), Fix::from_bits(3));
|
|
||||||
// 0.00011 -> 0000.0010 (tie to even)
|
|
||||||
assert_eq!(Fix::from_f32(3.0 / 32.0).unwrap(), Fix::from_bits(2));
|
|
||||||
// 0.00101 -> 0000.0010 (tie to even)
|
|
||||||
assert_eq!(Fix::from_f32(5.0 / 32.0).unwrap(), Fix::from_bits(2));
|
|
||||||
// 0.000011 -> 0000.0001 (nearest)
|
|
||||||
assert_eq!(Fix::from_f32(3.0 / 64.0).unwrap(), Fix::from_bits(1));
|
|
||||||
// 0.00001 -> 0000.0000 (tie to even)
|
|
||||||
assert_eq!(Fix::from_f32(1.0 / 32.0).unwrap(), Fix::from_bits(0));
|
|
||||||
// -0.00001 -> 0000.0000 (tie to even)
|
|
||||||
assert_eq!(Fix::from_f32(-1.0 / 32.0).unwrap(), Fix::from_bits(0));
|
|
||||||
// -0.0001 -> too small
|
|
||||||
assert!(Fix::from_f32(-1.0 / 16.0).is_none());
|
|
||||||
|
|
||||||
// 1111.1111 -> 1111.1111
|
|
||||||
assert_eq!(Fix::from_f32(255.0 / 16.0).unwrap(), Fix::from_bits(255));
|
|
||||||
// 1111.11111 -> too large (tie to even)
|
|
||||||
assert!(Fix::from_f32(511.0 / 32.0).is_none());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "f16")]
|
|
||||||
#[test]
|
|
||||||
fn to_f16() {
|
|
||||||
use half::f16;
|
|
||||||
for u in 0x00..=0xff {
|
|
||||||
let fu = FixedU8::<frac::U7>::from_bits(u);
|
|
||||||
assert_eq!(fu.to_f16(), f16::from_f32(u as f32 / 128.0));
|
|
||||||
let i = u as i8;
|
|
||||||
let fi = FixedI8::<frac::U7>::from_bits(i);
|
|
||||||
assert_eq!(fi.to_f16(), f16::from_f32(i as f32 / 128.0));
|
|
||||||
|
|
||||||
for hi in &[
|
|
||||||
0u32,
|
|
||||||
0x0000_0100,
|
|
||||||
0x7fff_ff00,
|
|
||||||
0x8000_0000,
|
|
||||||
0x8100_0000,
|
|
||||||
0xffff_fe00,
|
|
||||||
0xffff_ff00,
|
|
||||||
] {
|
|
||||||
let uu = *hi | u as u32;
|
|
||||||
let fuu = FixedU32::<frac::U7>::from_bits(uu);
|
|
||||||
assert_eq!(fuu.to_f16(), f16::from_f32(uu as f32 / 128.0));
|
|
||||||
let ii = uu as i32;
|
|
||||||
let fii = FixedI32::<frac::U7>::from_bits(ii);
|
|
||||||
assert_eq!(fii.to_f16(), f16::from_f32(ii as f32 / 128.0));
|
|
||||||
}
|
|
||||||
|
|
||||||
for hi in &[
|
|
||||||
0u128,
|
|
||||||
0x0000_0000_0000_0000_0000_0000_0000_0100,
|
|
||||||
0x7fff_ffff_ffff_ffff_ffff_ffff_ffff_ff00,
|
|
||||||
0x8000_0000_0000_0000_0000_0000_0000_0000,
|
|
||||||
0x8100_0000_0000_0000_0000_0000_0000_0000,
|
|
||||||
0xffff_ffff_ffff_ffff_ffff_ffff_ffff_fe00,
|
|
||||||
0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ff00,
|
|
||||||
] {
|
|
||||||
let uu = *hi | u as u128;
|
|
||||||
let fuu = FixedU128::<frac::U7>::from_bits(uu);
|
|
||||||
assert_eq!(fuu.to_f16(), f16::from_f64(uu as f64 / 128.0));
|
|
||||||
let ii = uu as i128;
|
|
||||||
let fii = FixedI128::<frac::U7>::from_bits(ii);
|
|
||||||
assert_eq!(fii.to_f16(), f16::from_f64(ii as f64 / 128.0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn to_f32() {
|
|
||||||
for u in 0x00..=0xff {
|
|
||||||
let fu = FixedU8::<frac::U7>::from_bits(u);
|
|
||||||
assert_eq!(fu.to_f32(), f32::from(u) / 128.0);
|
|
||||||
let i = u as i8;
|
|
||||||
let fi = FixedI8::<frac::U7>::from_bits(i);
|
|
||||||
assert_eq!(fi.to_f32(), f32::from(i) / 128.0);
|
|
||||||
|
|
||||||
for hi in &[
|
|
||||||
0u32,
|
|
||||||
0x0000_0100,
|
|
||||||
0x7fff_ff00,
|
|
||||||
0x8000_0000,
|
|
||||||
0x8100_0000,
|
|
||||||
0xffff_fe00,
|
|
||||||
0xffff_ff00,
|
|
||||||
] {
|
|
||||||
let uu = *hi | u32::from(u);
|
|
||||||
let fuu = FixedU32::<frac::U7>::from_bits(uu);
|
|
||||||
assert_eq!(fuu.to_f32(), uu as f32 / 128.0);
|
|
||||||
let ii = uu as i32;
|
|
||||||
let fii = FixedI32::<frac::U7>::from_bits(ii);
|
|
||||||
assert_eq!(fii.to_f32(), ii as f32 / 128.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
for hi in &[
|
|
||||||
0u128,
|
|
||||||
0x0000_0000_0000_0000_0000_0000_0000_0100,
|
|
||||||
0x7fff_ffff_ffff_ffff_ffff_ffff_ffff_ff00,
|
|
||||||
0x8000_0000_0000_0000_0000_0000_0000_0000,
|
|
||||||
0x8100_0000_0000_0000_0000_0000_0000_0000,
|
|
||||||
0xffff_ffff_ffff_ffff_ffff_ffff_ffff_fe00,
|
|
||||||
0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ff00,
|
|
||||||
] {
|
|
||||||
let uu = *hi | u128::from(u);
|
|
||||||
let fuu = FixedU128::<frac::U7>::from_bits(uu);
|
|
||||||
assert_eq!(fuu.to_f32(), (uu as f64 / 128.0) as f32);
|
|
||||||
let ii = uu as i128;
|
|
||||||
let fii = FixedI128::<frac::U7>::from_bits(ii);
|
|
||||||
assert_eq!(fii.to_f32(), (ii as f64 / 128.0) as f32);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn to_infinite_f32() {
|
|
||||||
// too_large is 1.ffff_ffff_ffff... << 127,
|
|
||||||
// which will be rounded to 1.0 << 128.
|
|
||||||
let too_large = FixedU128::<frac::U0>::max_value();
|
|
||||||
assert_eq!(too_large.count_ones(), 128);
|
|
||||||
assert!(too_large.to_f32().is_infinite());
|
|
||||||
|
|
||||||
// still_too_large is 1.ffff_ff << 127,
|
|
||||||
// which is exactly midway between 1.0 << 128 (even)
|
|
||||||
// and the largest normal f32 that is 1.ffff_fe << 127 (odd).
|
|
||||||
// The tie will be rounded to even, which is to 1.0 << 128.
|
|
||||||
let still_too_large = too_large << 103u32;
|
|
||||||
assert_eq!(still_too_large.count_ones(), 25);
|
|
||||||
assert!(still_too_large.to_f32().is_infinite());
|
|
||||||
|
|
||||||
// not_too_large is 1.ffff_feff_ffff... << 127,
|
|
||||||
// which will be rounded to 1.ffff_fe << 127.
|
|
||||||
let not_too_large = still_too_large - FixedU128::from_bits(1);
|
|
||||||
assert_eq!(not_too_large.count_ones(), 127);
|
|
||||||
assert!(!not_too_large.to_f32().is_infinite());
|
|
||||||
|
|
||||||
// min_128 is -1.0 << 127.
|
|
||||||
let min_i128 = FixedI128::<frac::U0>::min_value();
|
|
||||||
assert_eq!(min_i128.count_ones(), 1);
|
|
||||||
assert_eq!(min_i128.to_f32(), -(127f32.exp2()));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn to_f64() {
|
|
||||||
for u in 0x00..=0xff {
|
|
||||||
let fu = FixedU8::<frac::U7>::from_bits(u);
|
|
||||||
assert_eq!(fu.to_f32(), f32::from(u) / 128.0);
|
|
||||||
let i = u as i8;
|
|
||||||
let fi = FixedI8::<frac::U7>::from_bits(i);
|
|
||||||
assert_eq!(fi.to_f32(), f32::from(i) / 128.0);
|
|
||||||
|
|
||||||
for hi in &[
|
|
||||||
0u64,
|
|
||||||
0x0000_0000_0000_0100,
|
|
||||||
0x7fff_ffff_ffff_ff00,
|
|
||||||
0x8000_0000_0000_0000,
|
|
||||||
0x8100_0000_0000_0000,
|
|
||||||
0xffff_ffff_ffff_fe00,
|
|
||||||
0xffff_ffff_ffff_ff00,
|
|
||||||
] {
|
|
||||||
let uu = *hi | u64::from(u);
|
|
||||||
let fuu = FixedU64::<frac::U7>::from_bits(uu);
|
|
||||||
assert_eq!(fuu.to_f64(), uu as f64 / 128.0);
|
|
||||||
let ii = uu as i64;
|
|
||||||
let fii = FixedI64::<frac::U7>::from_bits(ii);
|
|
||||||
assert_eq!(fii.to_f64(), ii as f64 / 128.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
for hi in &[
|
|
||||||
0u128,
|
|
||||||
0x0000_0000_0000_0000_0000_0000_0000_0100,
|
|
||||||
0x7fff_ffff_ffff_ffff_ffff_ffff_ffff_ff00,
|
|
||||||
0x8000_0000_0000_0000_0000_0000_0000_0000,
|
|
||||||
0x8100_0000_0000_0000_0000_0000_0000_0000,
|
|
||||||
0xffff_ffff_ffff_ffff_ffff_ffff_ffff_fe00,
|
|
||||||
0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ff00,
|
|
||||||
] {
|
|
||||||
let uu = *hi | u128::from(u);
|
|
||||||
let fuu = FixedU128::<frac::U7>::from_bits(uu);
|
|
||||||
assert_eq!(fuu.to_f64(), uu as f64 / 128.0);
|
|
||||||
let ii = uu as i128;
|
|
||||||
let fii = FixedI128::<frac::U7>::from_bits(ii);
|
|
||||||
assert_eq!(fii.to_f64(), ii as f64 / 128.0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue