1use crate::*;
2use bitvec::field::BitField;
3use fraction::{prelude::*, Num, ToPrimitive};
4use core::str::FromStr;
5
6#[derive(Debug, Clone, PartialEq, Eq)]
8pub struct Float {
9 pub format: Format,
10 pub bits: BitPattern,
11}
12
13impl Float {
14 pub fn from_str(format: Format, s: &str) -> Result<Self, error::Error> {
21 match s.chars().next() {
23 Some('0'..='9' | '+' | '-') => {},
24 _ => return Err(error::Error::ParseStringError),
25 }
26
27 let sign = s.starts_with('-');
28 let s = if sign { &s[1..] } else { s };
29
30 if sign && !format.signed {
31 return Err(error::Error::NegativeSign);
32 }
33
34 let frac = BigFraction::from_str(s).map_err(|_| error::Error::ParseStringError)?;
35
36 let (mut int, mut frac) = (
38 BigUint::from(frac.clone().numer().unwrap() / frac.clone().denom().unwrap()),
39 frac.fract(),
40 );
41
42 let mut int_bits = String::new();
43 let mut frac_bits = String::new();
44
45 let exp = match int > BigUint::from(0u32) {
46 false if frac == BigFraction::from(0u32) => {
47 -(format.excess as i128)
48 },
49 true => {
50 let mut exp = 0i128;
51
52 while int > BigUint::from(1u32) {
54 int_bits.push(if int.clone() % BigUint::from(2u32) == BigUint::from(1u32) { '1' } else { '0' });
55 int /= 2u32;
56 exp += 1;
57 }
58
59 while frac != BigFraction::from(0u32) && int_bits.len() + frac_bits.len() < format.mant {
61 frac *= BigFraction::from(2u32);
62 frac_bits.insert(0, if frac > BigFraction::from(1u32) { '1' } else { '0' });
63 frac %= BigFraction::from(1u32);
64 }
65
66 exp
67 },
68 false => {
69 let mut exp = 0i128;
70
71 loop {
73 frac *= BigFraction::from(2u32);
74 exp -= 1;
75
76 if frac > BigFraction::from(1u32) {
77 frac %= BigFraction::from(1u32);
78 break;
79 }
80 }
81
82 while frac != BigFraction::from(0u32) && frac_bits.len() < format.mant {
84 frac *= BigFraction::from(2u32);
85 frac_bits.insert(0, if frac > BigFraction::from(1u32) { '1' } else { '0' });
86
87 frac %= BigFraction::from(1u32);
88 }
89
90 exp
91 },
92 };
93
94 let len = int_bits.len() + frac_bits.len();
95
96 let int_bits = int_bits
97 .chars()
98 .rev()
99 .take(format.mant)
100 .collect::<String>();
101
102 let frac_bits = frac_bits
103 .chars()
104 .rev()
105 .chain(std::iter::repeat('0').take(if len < format.mant {
106 format.mant - len
107 } else {
108 0
109 }))
110 .collect::<String>();
111
112 if exp < -(format.excess as i128) || exp >= ((1 << format.exp) - format.excess) as i128 {
113 return Err(error::Error::OutOfRange);
114 }
115
116 let exp = exp + format.excess as i128;
117
118 let signed = format.signed;
119 let width = format.exp;
120 Self::from_fields(
121 format,
122 if signed { Some(sign) } else { None },
123 format!("0b{:0width$b}", exp, width = width as usize).as_str(),
124 ("0b".to_owned() + &int_bits + &frac_bits).as_str(),
125 )
126 }
127
128 pub fn from_bits(format: Format, bits: BitPattern) -> Result<Float, error::Error> {
135 let mut formatted_bits = BitPattern::new();
136
137 if bits.len() < format.len() {
138 formatted_bits.extend(std::iter::repeat(false).take(format.len() - bits.len()));
139 formatted_bits.extend(bits.into_iter());
140 } else if bits
141 .iter()
142 .take(bits.len() - format.len())
143 .any(|b| b == true)
144 {
145 return Err(error::Error::InsufficientBitsForBitPattern);
146 } else {
147 let len = bits.len();
148 formatted_bits.extend(bits.into_iter().skip(len - format.len()));
149 }
150
151 Ok(Float {
152 format,
153 bits: formatted_bits,
154 })
155 }
156
157 pub fn from_comps(format: Format, comps: Components) -> Result<Float, error::Error> {
164 let mut bits = BitPattern::new();
165
166 let comps_format = comps.format();
167
168 if format.signed != comps_format.signed {
170 return Err(error::Error::MismatchedSignBit);
171 }
172
173 if let Some(sign) = comps.sign {
174 bits.push(sign);
175 }
176
177 let exp = comps.exp.into_iter();
179 let mant = comps.mant.into_iter();
180
181 if comps_format.exp < format.exp {
182 bits.extend(std::iter::repeat(false).take((format.exp - comps_format.exp) as usize));
183 bits.extend(exp);
184 } else if exp
185 .clone()
186 .take((comps_format.exp - format.exp) as usize)
187 .any(|b| b == true)
188 {
189 return Err(error::Error::InsufficientExponentBits);
190 } else {
191 bits.extend(exp.skip((comps_format.exp - format.exp) as usize));
192 }
193
194 if comps_format.mant < format.mant {
195 bits.extend(std::iter::repeat(false).take(format.mant - comps_format.mant));
196 bits.extend(mant);
197 } else if mant
198 .clone()
199 .take(comps_format.mant - format.mant)
200 .any(|b| b == true)
201 {
202 return Err(error::Error::InsufficientMantissaBits);
203 } else {
204 bits.extend(mant.skip(comps_format.mant - format.mant));
205 }
206
207 Ok(Float::from_bits(format, bits).unwrap())
208 }
209
210 pub fn from_fields(format: Format, sign: Option<bool>, exp: &str, mant: &str) -> Result<Float, error::Error> {
222 let comps = Components::new(
223 sign,
224 exp,
225 mant,
226 )?;
227
228 Float::from_comps(
229 format,
230 comps
231 )
232 }
233
234 pub fn get_start_indices(&self) -> (usize, usize) {
237 (
238 self.format.signed as usize,
239 self.format.signed as usize + self.format.exp as usize,
240 )
241 }
242
243 pub fn to_comps(&self) -> Components {
245 let signed = self.format.signed;
246 let exp_range = signed as usize..(signed as usize + self.format.exp as usize);
247 let mant_range = exp_range.end..(exp_range.end + self.format.mant as usize);
248
249 let sign = match signed {
250 true => Some(self.bits[0]),
251 false => None,
252 };
253
254 let exp = self.bits[exp_range].to_owned();
255 let mant = self.bits[mant_range].to_owned();
256
257 Components { sign, exp, mant }
258 }
259
260 pub fn to_f32(&self) -> f32 {
263 let Components { sign, exp, mant } = self.to_comps();
264
265 let exp = i64::from_str_radix(&exp.to_bin_string(), 2).unwrap();
266 let mant = BigUint::from_str_radix(&mant.to_bin_string(), 2).unwrap();
267
268 let sign = match sign {
269 Some(true) => -1f32,
270 Some(false) => 1f32,
271 None => 1f32,
272 };
273
274 let exp = 2f32.powi((exp - self.format.excess as i64) as i32);
275 let mant = mant.to_f32().unwrap() / num_traits::pow(2f32, self.format.mant) + 1f32;
276
277 sign * exp * mant
278 }
279
280 pub fn to_f64(&self) -> f64 {
283 let Components { sign, exp, mant } = self.to_comps();
284
285 let exp = i64::from_str_radix(&exp.to_bin_string(), 2).unwrap();
286 let mant = BigUint::from_str_radix(&mant.to_bin_string(), 2).unwrap();
287
288 let sign = match sign {
289 Some(true) => -1f64,
290 Some(false) => 1f64,
291 None => 1f64,
292 };
293
294 let exp = 2f64.powi((exp - self.format.excess as i64) as i32);
295 let mant = mant.to_f64().unwrap() / num_traits::pow(2f64, self.format.mant) + 1f64;
296
297 sign * exp * mant
298 }
299
300 pub fn to_f32_raw(&self) -> f32 {
303 f32::from_bits(self.bits.load_le::<u32>())
304 }
305
306 pub fn to_f64_raw(&self) -> f64 {
309 f64::from_bits(self.bits.load_le::<u64>())
310 }
311}
312
313impl From<f32> for Float {
314 fn from(f: f32) -> Float {
316 let bits = f.to_bits();
317 let format = Format::ieee_binary32();
318 Float::from_bits(format, BitPattern::from_value(bits)).unwrap()
319 }
320}
321
322#[cfg(target_pointer_width = "64")]
323impl From<f64> for Float {
324 fn from(f: f64) -> Float {
327 let bits = f.to_bits();
328 let format = Format::ieee_binary64();
329 Float::from_bits(format, BitPattern::from_value(bits)).unwrap()
330 }
331}
332
333impl std::fmt::Display for Float {
334 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
335 let comps = self.to_comps();
336
337 if let Some(s) = (self.format.interpret)(&comps) {
338 return write!(f, "{}", s);
339 }
340
341 let sign = match comps.sign {
343 Some(true) => "-",
344 _ => "",
345 };
346
347 let exp =
349 BigInt::from_str_radix(&comps.exp.to_bin_string(), 2).unwrap() - self.format.excess.clone();
350
351 let exp = match exp < BigInt::from(0i32) {
352 true => BigFraction::new(BigUint::from(1u32), BigUint::from(2u32) << ((-exp).to_usize().unwrap() - 1)),
353 false => BigFraction::from(BigUint::from(1u32) << exp.to_usize().unwrap()),
354 };
355
356 let frac = comps.mant
358 .iter()
359 .fold((BigUint::from(0u32), BigUint::from(0u32)),
360 |(numer, denom), b| {
361 (
362 numer * 2u32 + if *b { 1u32 } else { 0u32 },
363 denom * 2u32 + 1u32,
364 )
365 }
366 );
367
368 let frac =
369 BigFraction::from(1u32)
370 + BigFraction::new(frac.0, frac.1);
371
372 let value = frac * exp;
373
374 if let Some(prec) = f.precision() {
376 return write!(f, "{}{}", sign, format!("{:.1$}", value, prec))
377 }
378
379 if value > BigFraction::from(9999999u32) {
380 return write!(f, "{}{}", sign, BigUint::from(value.clone().numer().unwrap() / value.clone().denom().unwrap()))
381 }
382
383 let prec = if value > BigFraction::from(999999u32) {
384 1
385 } else if value > BigFraction::from(99999u32) {
386 2
387 } else if value > BigFraction::from(9999u32) {
388 3
389 } else if value > BigFraction::from(999u32) {
390 4
391 } else if value > BigFraction::from(99u32) {
392 5
393 } else if value > BigFraction::from(9u32) {
394 6
395 } else if value >= BigFraction::from(1u32) {
396 7
397 } else {
398 let mut value = value.fract();
399 let mut prec = 8;
400
401 loop {
402 value *= BigFraction::from(10u32);
403 if value.trunc() > BigFraction::from(0u32) {
404 break prec;
405 }
406 prec += 1;
407 }
408 };
409
410 write!(f, "{}{}", sign, format!("{:.1$}", value, prec))
411 }
412}