work
[pspp] / rust / src / hexfloat.rs
1 use num::Float;
2 use std::{num::FpCategory, fmt::{Display, Formatter, Result}};
3
4 pub struct HexFloat<T: Float>(pub T);
5
6 impl<T: Float> Display for HexFloat<T> {
7     fn fmt(&self, f: &mut Formatter<'_>) -> Result {
8         let sign = if self.0.is_sign_negative() { "-" } else { "" };
9         match self.0.classify() {
10             FpCategory::Nan => return write!(f, "NaN"),
11             FpCategory::Infinite => return write!(f, "{sign}Infinity"),
12             FpCategory::Zero => return write!(f, "{sign}0.0"),
13             _ => (),
14         };
15         let (significand, mut exponent, _) = self.0.integer_decode();
16         let mut hex_sig = format!("{:x}", significand);
17         while hex_sig.ends_with('0') {
18             hex_sig.pop();
19             exponent += 4;
20         }
21         match hex_sig.len() {
22             0 => write!(f, "{sign}0.0"),
23             1 => write!(f, "{sign}0x{hex_sig}.0p{exponent}"),
24             len => write!(
25                 f,
26                 "{sign}0x{}.{}p{}",
27                 hex_sig.chars().next().unwrap(),
28                 &hex_sig[1..],
29                 exponent + 4 * (len as i16 - 1)
30             ),
31         }
32     }
33 }
34
35 #[cfg(test)]
36 mod hex_float_tests {
37     use crate::HexFloat;
38     use num::Float;
39
40     #[test]
41     fn test() {
42         assert_eq!(format!("{}", HexFloat(1.0)), "0x1.0p0");
43         assert_eq!(format!("{}", HexFloat(123.0)), "0x1.ecp6");
44         assert_eq!(format!("{}", HexFloat(1.0 / 16.0)), "0x1.0p-4");
45         assert_eq!(format!("{}", HexFloat(f64::infinity())), "Infinity");
46         assert_eq!(format!("{}", HexFloat(f64::neg_infinity())), "-Infinity");
47         assert_eq!(format!("{}", HexFloat(f64::nan())), "NaN");
48         assert_eq!(format!("{}", HexFloat(0.0)), "0.0");
49         assert_eq!(format!("{}", HexFloat(f64::neg_zero())), "-0.0");
50     }
51 }
52