pub trait FloatParts: std::fmt::Debug {
#[cfg(test)]
fn exponent_normal_max() -> u16;
#[cfg(test)]
fn fraction_normal_max() -> u64;
fn exponent_bit_position() -> u8;
fn sign_bit_position() -> u8;
fn to_bits(&self) -> u64;
fn from_bits(bitz: u64) -> Self;
fn exponent(&self) -> u16 {
let mut bits = FloatParts::to_bits(self);
bits &= (0x1 << Self::sign_bit_position()) - 1;
(bits >> Self::exponent_bit_position()) as u16
}
fn fraction(&self) -> u64 {
let mut bits = FloatParts::to_bits(self);
bits &= (0x1 << Self::exponent_bit_position()) - 1;
bits
}
fn is_sign_negative(&self) -> bool {
let bits = self.to_bits();
(bits >> Self::sign_bit_position()) != 0
}
fn compose(sign_is_negative: bool, exponent: u16, fraction: u64) -> u64 {
let sign: u64 = if sign_is_negative { 0x1 } else { 0x0 };
(sign << Self::sign_bit_position())
| (exponent as u64) << Self::exponent_bit_position()
| fraction
}
}
impl FloatParts for f32 {
#[cfg(test)]
fn exponent_normal_max() -> u16 {
0xfe
}
#[cfg(test)]
fn fraction_normal_max() -> u64 {
0x7fffff
}
fn exponent_bit_position() -> u8 {
23
}
fn sign_bit_position() -> u8 {
31
}
fn to_bits(&self) -> u64 {
f32::to_bits(*self) as u64
}
fn from_bits(bitz: u64) -> Self {
f32::from_bits(bitz as u32)
}
}
impl FloatParts for f64 {
#[cfg(test)]
fn exponent_normal_max() -> u16 {
0x7fe
}
#[cfg(test)]
fn fraction_normal_max() -> u64 {
0xfffffffffffff
}
fn exponent_bit_position() -> u8 {
52
}
fn sign_bit_position() -> u8 {
63
}
fn to_bits(&self) -> u64 {
f64::to_bits(*self)
}
fn from_bits(bitz: u64) -> Self {
f64::from_bits(bitz)
}
}
#[cfg(test)]
mod test {
use super::FloatParts;
use crate::*;
fn f32_exp() -> BoxGen<u16> {
gens::u16::ranged(0..=f32::exponent_normal_max())
}
fn f64_exp() -> BoxGen<u16> {
gens::u16::ranged(0..=f64::exponent_normal_max())
}
fn f32_frac() -> BoxGen<u64> {
gens::u64::ranged(0..=f32::fraction_normal_max())
}
fn f64_frac() -> BoxGen<u64> {
gens::u64::ranged(0..=f64::fraction_normal_max())
}
fn compose_f32(
sign_is_negative: bool,
exponent: u16,
fraction: u64,
) -> f32 {
f32::from_bits(f32::compose(sign_is_negative, exponent, fraction) as u32)
}
fn compose_f64(
sign_is_negative: bool,
exponent: u16,
fraction: u64,
) -> f64 {
f64::from_bits(f64::compose(sign_is_negative, exponent, fraction))
}
#[test]
fn roundtrip_test_f32() {
crate::monkey_test()
.with_generator(
f32_exp().zip(f32_frac()).zip(crate::gens::bool::any()),
)
.assert_true(|((e, f), s)| {
compose_f32(s, e, f).is_sign_negative() == s
})
.assert_true(|((e, f), s)| compose_f32(s, e, f).exponent() == e)
.assert_true(|((e, f), s)| compose_f32(s, e, f).fraction() == f);
}
#[test]
fn roundtrip_test_f64() {
crate::monkey_test()
.with_generator(
f64_exp().zip(f64_frac()).zip(crate::gens::bool::any()),
)
.assert_true(|((e, f), s)| {
compose_f64(s, e, f).is_sign_negative() == s
})
.assert_true(|((e, f), s)| compose_f64(s, e, f).exponent() == e)
.assert_true(|((e, f), s)| compose_f64(s, e, f).fraction() == f);
}
}