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
use crate::{ConversionResult, FloatLiteral};
use core::ops;
macro_rules! impl_fpformat {
($fp_type:ty, $bits_type:ty, $exponent_bits: literal, $mantissa_bits: literal, $from_bits: expr, $infinity: expr, $max_exp: expr, $min_exp: expr) => {
impl FPFormat for $fp_type {
fn from_literal(literal: FloatLiteral) -> ConversionResult<$fp_type> {
const EXPONENT_BITS: u32 = $exponent_bits;
const MANTISSA_BITS: u32 = $mantissa_bits;
const TOTAL_BITS: u32 = 1 + EXPONENT_BITS + MANTISSA_BITS;
const EXPONENT_BIAS: u32 = (1 << (EXPONENT_BITS - 1)) - 1;
let mut exponent_offset: i32 = literal.decimal_offset * 4;
if literal.digits.is_empty() {
return ConversionResult::Precise(0.0);
}
let mut was_truncated = false;
let mut mantissa_result: $bits_type = 0;
for (index, digit) in literal.digits.iter().enumerate() {
if index as u32 * 4 > MANTISSA_BITS {
was_truncated = true;
break;
}
let mut digit_value = *digit as $bits_type;
digit_value <<= TOTAL_BITS - (index as u32 + 1) * 4;
mantissa_result |= digit_value;
}
let leading_zeros = mantissa_result.leading_zeros();
exponent_offset -= leading_zeros as i32 + 1;
mantissa_result <<= leading_zeros + 1;
mantissa_result >>= TOTAL_BITS - MANTISSA_BITS;
let final_exponent = exponent_offset + literal.exponent;
if final_exponent < $min_exp - 1 {
if literal.is_positive {
return ConversionResult::Imprecise(0.0);
} else {
return ConversionResult::Imprecise(-0.0);
};
}
if final_exponent > $max_exp - 1 {
if literal.is_positive {
return ConversionResult::Imprecise($infinity);
} else {
return ConversionResult::Imprecise(-$infinity);
};
}
let exponent_result: $bits_type =
((final_exponent + EXPONENT_BIAS as i32) as $bits_type) << MANTISSA_BITS;
let sign_result: $bits_type =
(!literal.is_positive as $bits_type) << (MANTISSA_BITS + EXPONENT_BITS);
let float_value = $from_bits(sign_result | exponent_result | mantissa_result);
if was_truncated {
ConversionResult::Imprecise(float_value)
} else {
ConversionResult::Precise(float_value)
}
}
}
};
}
pub trait FPFormat: ops::Neg<Output = Self> + Sized + Copy {
fn from_literal(literal: FloatLiteral) -> ConversionResult<Self>;
}
impl_fpformat!(
f32,
u32,
8,
23,
f32::from_bits,
core::f32::INFINITY,
core::f32::MAX_EXP,
core::f32::MIN_EXP
);
impl_fpformat!(
f64,
u64,
11,
52,
f64::from_bits,
core::f64::INFINITY,
core::f64::MAX_EXP,
core::f64::MIN_EXP
);