1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
use std::fmt::{Binary, Debug, Display};

pub trait FloatDbg<U, S>: Copy + Sized + Debug
where
    U: Default + Binary + Display + PartialEq + std::ops::BitAnd<Output = U>,
    S: Display,
{
    const WIDTH: usize;
    const EXP_WIDTH: usize;
    const FRACT_WIDTH: usize;

    const SIGN_MASK: U;
    const EXP_MASK: U;
    const FRACT_MASK: U;

    const EXP_BIAS: S;

    fn to_bits(self) -> U;
    fn sign_bit(self) -> bool {
        self.to_bits() & Self::SIGN_MASK != U::default()
    }

    fn biased_exponent(self) -> U;
    fn unbiased_exponent(self) -> S;

    fn fraction(self) -> U;
    fn significand(self) -> U;

    fn explain(self) {
        println!("value = {:?}", self);
        println!("bits: {:0width$b}", self.to_bits(), width = Self::WIDTH);
        println!(
            "      ±{:^<e$}{:_<f$}",
            "",
            "",
            e = Self::EXP_WIDTH,
            f = Self::FRACT_WIDTH
        );
        println!("sign: {}", if self.sign_bit() { "-" } else { "+" });
        println!(
            "exponent = {} - {} = {}",
            self.biased_exponent(),
            Self::EXP_BIAS,
            self.unbiased_exponent()
        );
        println!(
            "significand = 2^{} + {} = {}",
            Self::FRACT_WIDTH,
            self.fraction(),
            self.significand()
        );
    }
}

macro_rules! impl_FloatDbg {
    ($F:ty, $U:ty, $S:ty; $width:expr, $exp_width:expr, $frac_width:expr) => {
        impl FloatDbg<$U, $S> for $F {
            const WIDTH: usize = $width;
            const EXP_WIDTH: usize = $exp_width;
            const FRACT_WIDTH: usize = $frac_width;

            const SIGN_MASK: $U = 1 << (Self::WIDTH - 1);
            const EXP_MASK: $U = ((1 << Self::EXP_WIDTH) - 1) << Self::FRACT_WIDTH;
            const FRACT_MASK: $U = (1 << Self::FRACT_WIDTH) - 1;

            const EXP_BIAS: $S = (1 << (Self::EXP_WIDTH - 1)) - 1;

            fn to_bits(self) -> $U {
                self.to_bits()
            }

            fn biased_exponent(self) -> $U {
                (self.to_bits() & Self::EXP_MASK) >> Self::FRACT_WIDTH
            }

            fn unbiased_exponent(self) -> $S {
                (self.biased_exponent() as $S).wrapping_sub(Self::EXP_BIAS)
            }

            fn fraction(self) -> $U {
                self.to_bits() & Self::FRACT_MASK
            }

            fn significand(self) -> $U {
                self.fraction() + (1 << Self::FRACT_WIDTH)
            }
        }
    };
}

impl_FloatDbg!(f32, u32, i32; 32, 8, 23);
impl_FloatDbg!(f64, u64, i64; 64, 11, 52);

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        let result = 2 + 2;
        assert_eq!(result, 4);
    }
}