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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
use super::Numeric;
use std::ops::{
    Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign,
};

/// A trait shared by all the floating point types.
pub trait FloatingPoint:
    Numeric
    + Neg<Output = Self>
    + Add<Self, Output = Self>
    + AddAssign<Self>
    + Div<Self, Output = Self>
    + DivAssign<Self>
    + Mul<Self, Output = Self>
    + MulAssign<Self>
    + Rem<Self, Output = Self>
    + RemAssign<Self>
    + Sub<Self, Output = Self>
    + SubAssign<Self>
{
    /// Raises a float to an integer power.
    fn powi(self, power: i32) -> Self;

    /// Rounds the float to the closest integer.
    fn round(self) -> Self;

    /// Keeps the fractional part of the number.
    fn fract(self) -> Self;

    /// Remainder of the euclidean division.
    fn rem_euclid(self, rhs: Self) -> Self;

    /// Returns the square root of the input float.
    fn sqrt(self) -> Self;

    /// Returns the natural logarithm of the input float.
    fn ln(self) -> Self;

    /// Returns the absolute value of the input float.
    fn abs(self) -> Self;

    /// Returns the floor value of the input float.
    fn floor(self) -> Self;

    /// Returns a bit representation of the float, with the sign, exponent, and mantissa bits
    /// separated by whitespaces for increased readability.
    fn to_bit_string(&self) -> String;
}

macro_rules! implement {
    ($Type: tt, $bits:expr) => {
        impl Numeric for $Type {
            const BITS: usize = $bits;
            const ZERO: Self = 0.;
            const ONE: Self = 1.;
            const TWO: Self = 2.;
            const MAX: Self = <$Type>::MAX;
        }
        impl FloatingPoint for $Type {
            fn powi(self, power: i32) -> Self {
                self.powi(power)
            }
            fn round(self) -> Self {
                self.round()
            }
            fn fract(self) -> Self {
                self.fract()
            }
            fn rem_euclid(self, rhs: Self) -> Self {
                self.rem_euclid(rhs)
            }
            fn sqrt(self) -> Self {
                self.sqrt()
            }
            fn ln(self) -> Self {
                self.ln()
            }
            fn abs(self) -> Self {
                self.abs()
            }
            fn floor(self) -> Self {
                self.floor()
            }
            fn to_bit_string(&self) -> String {
                if Self::BITS == 32 {
                    let mut bit_string = format!("{:032b}", self.to_bits());
                    bit_string.insert(1, ' ');
                    bit_string.insert(10, ' ');
                    format!("{}", bit_string)
                } else {
                    let mut bit_string = format!("{:064b}", self.to_bits());
                    bit_string.insert(1, ' ');
                    bit_string.insert(13, ' ');
                    format!("{}", bit_string)
                }
            }
        }
    };
}

implement!(f64, 64);
implement!(f32, 32);

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_f64_binary_rep() {
        let a = 1123214.4321432 as f64;
        let b = a.to_bit_string();
        assert_eq!(
            b,
            "0 10000010011 0001001000111000111001101110101000001110111111001111".to_string()
        );
    }

    #[test]
    fn test_f32_binary_rep() {
        let a = -1.27666388717e+27 as f32;
        let b = a.to_bit_string();
        assert_eq!(b, "1 11011001 00001000000000100000011".to_string());
    }
}