1//! Floating point fractional number for a single-precision float.
2
3use super::F32;
4use super::{EXPONENT_BIAS, MANTISSA_BITS, MANTISSA_MASK};
5
6impl F32 {
7 /// Returns the fractional part of a number with sign.
8 pub fn fract(self) -> Self {
9 let x_bits = self.to_bits();
10 let exponent = self.extract_exponent_value();
11
12 // we know it is *only* fraction
13 if exponent < 0 {
14 return self;
15 }
16
17 // find the part of the fraction that would be left over
18 let fractional_part = x_bits.overflowing_shl(exponent as u32).0 & MANTISSA_MASK;
19
20 // if there isn't a fraction we can just return 0
21 if fractional_part == 0 {
22 // TODO: most people don't actually care about -0.0,
23 // so would it be better to just not copysign?
24 return Self(0.0).copysign(self);
25 }
26
27 // Note: alternatively this could use -1.0, but it's assumed subtraction would be more costly
28 // example: 'let new_exponent_bits = 127_u32.overflowing_shl(23_u32).0)) - 1.0'
29 let exponent_shift: u32 = (fractional_part.leading_zeros() - (32 - MANTISSA_BITS)) + 1;
30
31 let fractional_normalized: u32 =
32 fractional_part.overflowing_shl(exponent_shift).0 & MANTISSA_MASK;
33
34 let new_exponent_bits = (EXPONENT_BIAS - (exponent_shift))
35 .overflowing_shl(MANTISSA_BITS)
36 .0;
37
38 Self::from_bits(fractional_normalized | new_exponent_bits).copysign(self)
39 }
40}
41
42#[cfg(test)]
43mod tests {
44 use super::F32;
45
46 #[test]
47 fn sanity_check() {
48 // fraction check actually won't be the same, though technically exactly accurate
49 // so we test by adding back the number removed.
50 assert_eq!(F32(2.9).fract().0 + 2.0, 2.9);
51 assert_eq!(F32(-1.1).fract().0 - 1.0, -1.1);
52 assert_eq!(F32(-0.1).fract().0, -0.1);
53 assert_eq!(F32(0.0).fract().0, 0.0);
54 assert_eq!(F32(1.0).fract().0 + 1.0, 1.0);
55 assert_eq!(F32(1.1).fract().0 + 1.0, 1.1);
56
57 assert_eq!(F32(-100_000_000.13425345345).fract().0, -0.0);
58 assert_eq!(F32(100_000_000.13425345345).fract().0, 0.0);
59 }
60}
61