1use std::fmt::{Display, Error, Formatter};
8use std::str::FromStr;
9
10#[derive(Eq, PartialEq, Debug)]
15pub enum Floating {
16 Normal {
18 exponent: i16,
20 mantissa: String,
22 is_negative: bool,
24 },
25 Abnormal(String),
27}
28
29impl From<f64> for Floating {
30 fn from(x: f64) -> Self {
31 if !x.is_normal() {
32 return Floating::Abnormal(format!("{}", x));
33 }
34 let is_negative = x < 0.;
35 let x = if is_negative { -x } else { x };
36 let x = format!("{:e}", x);
37 let mut parts = x.splitn(2, "e");
38 if let Some(mantissa) = parts.next() {
39 let mut mantissa = mantissa.to_string();
40 if mantissa.len() > 1 {
41 mantissa.remove(1);
42 }
43 let exponent = i16::from_str(parts.next().expect("float repr should have exponent"))
44 .expect("exponent should be integer");
45 Floating::Normal {
46 exponent,
47 mantissa,
48 is_negative,
49 }
50 } else {
51 panic!("I think thi sis impossible...");
52 }
53 }
54}
55impl From<f32> for Floating {
56 fn from(x: f32) -> Self {
57 if !x.is_normal() {
58 return Floating::Abnormal(format!("{}", x));
59 }
60 let is_negative = x < 0.;
61 let x = if is_negative { -x } else { x };
62 let x = format!("{:e}", x);
63 let mut parts = x.splitn(2, "e");
64 if let Some(mantissa) = parts.next() {
65 let mut mantissa = mantissa.to_string();
66 if mantissa.len() > 1 {
67 mantissa.remove(1);
68 }
69 let exponent = i16::from_str(parts.next().expect("float repr should have exponent"))
70 .expect("exponent should be integer");
71 Floating::Normal {
72 exponent,
73 mantissa,
74 is_negative,
75 }
76 } else {
77 panic!("I think thi sis impossible...");
78 }
79 }
80}
81
82#[test]
83fn to_floating() {
84 assert_eq!(
85 Floating::from(1.0),
86 Floating::Normal {
87 exponent: 0,
88 mantissa: "1".to_string(),
89 is_negative: false
90 }
91 );
92 assert_eq!(
93 Floating::from(1.2e10),
94 Floating::Normal {
95 exponent: 10,
96 mantissa: "12".to_string(),
97 is_negative: false
98 }
99 );
100}
101
102impl Floating {
103 pub fn fmt_with(
109 &self,
110 f: &mut Formatter,
111 e: &str,
112 after_e: &str,
113 e_waste: usize,
114 power_ten: Option<&str>,
115 ) -> Result<(), Error> {
116 match self {
117 Floating::Abnormal(s) => f.write_str(&s),
118 Floating::Normal {
119 exponent,
120 mantissa,
121 is_negative,
122 } => {
123 let e_waste = e_waste as i16;
124 if *is_negative {
125 f.write_str("-")?;
126 }
127 if *exponent > 1 + e_waste || *exponent < -2 - e_waste {
128 if mantissa.len() > 1 {
129 let (a, r) = mantissa.split_at(1);
130 f.write_str(a)?;
131 f.write_str(".")?;
132 f.write_str(r)?;
133 f.write_str(e)?;
134 exponent.fmt(f)?;
135 f.write_str(after_e)
136 } else if mantissa == "1" && power_ten.is_some() {
137 f.write_str(power_ten.unwrap())?;
140 exponent.fmt(f)?;
141 f.write_str(after_e)
142 } else {
143 f.write_str(mantissa)?;
144 f.write_str(e)?;
145 exponent.fmt(f)?;
146 f.write_str(after_e)
147 }
148 } else {
149 if *exponent + 1 > mantissa.len() as i16 {
150 f.write_str(mantissa)?;
151 for _ in 0..*exponent as usize + 1 - mantissa.len() {
152 f.write_str("0")?;
153 }
154 Ok(())
155 } else if *exponent < 0 {
156 f.write_str("0.")?;
157 for _ in 0..-exponent - 1 {
158 f.write_str("0")?;
159 }
160 f.write_str(&mantissa)
161 } else if *exponent + 1 == mantissa.len() as i16 {
162 f.write_str(mantissa)
163 } else {
164 let (a, b) = mantissa.split_at(*exponent as usize + 1);
165 f.write_str(a)?;
166 f.write_str(".")?;
167 f.write_str(b)
168 }
169 }
170 }
171 }
172 }
173}
174
175impl Display for Floating {
176 fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
177 self.fmt_with(f, "e", "", 1, None)
178 }
179}
180
181#[test]
182fn display() {
183 assert_eq!(&format!("{}", Floating::from(1.0)), "1");
184 assert_eq!(&format!("{}", Floating::from(0.1)), "0.1");
185 assert_eq!(&format!("{}", Floating::from(1e-10)), "1e-10");
186 assert_eq!(&format!("{}", Floating::from(1.2e-10)), "1.2e-10");
187 assert_eq!(&format!("{}", Floating::from(120.)), "120");
188 assert_eq!(&format!("{}", Floating::from(123.)), "123");
189 assert_eq!(&format!("{}", Floating::from(123.4)), "123.4");
190 assert_eq!(&format!("{}", Floating::from(1.2e6)), "1.2e6");
191 assert_eq!(&format!("{}", Floating::from(0.001)), "0.001");
192 assert_eq!(&format!("{}", Floating::from(0.0001)), "1e-4");
193 assert_eq!(&format!("{}", Floating::from(0.001234)), "0.001234");
194}