awint_ext/fp_struct/ieee.rs
1use core::borrow::BorrowMut;
2
3use awint_core::{Bits, InlAwi};
4
5use crate::FP;
6
7/// A minimal `FP<inlawi_ty!(25)>` real number representation of an IEEE-754 32
8/// bit floating point number.
9///
10/// This derives from 23 mantissa bits, the omitted leading 1 bit, and sign bit.
11/// This cannot represent the infinity and NaN cases, but subnormal values can
12/// be represented. Canonically, the fixed point is always 150 (the 127 bias
13/// plus 23 mantissa bits) minus the raw IEEE-754 exponent.
14pub type F32 = FP<InlAwi<25, { Bits::unstable_raw_digits(25) }>>;
15
16/// A minimal `FP<inlawi_ty!(54)>` real number representation of an IEEE-754 64
17/// bit floating point number.
18///
19/// This derives from 52 mantissa bits, the omitted leading 1 bit, and sign bit.
20/// This cannot represent the infinity and NaN cases, but subnormal values can
21/// be represented. Canonically, the fixed point is always 1075 (the 1023 bias
22/// plus 52 mantissa bits) minus the raw IEEE-754 exponent.
23pub type F64 = FP<InlAwi<54, { Bits::unstable_raw_digits(54) }>>;
24
25impl F32 {
26 /// Translates the IEEE-754 value of `f` to an [F32](crate::fp::F32),
27 /// handling subnormal values correctly and casting the values of
28 /// infinities and NaN to zero (with the fixed point always being 150
29 /// minus the raw exponent).
30 pub fn from_f32(f: f32) -> Self {
31 let exponent = ((f.to_bits() >> 23) & ((1 << 8) - 1)) as u8;
32 let sign = (f.to_bits() >> 31) != 0;
33 let mantissa = f.to_bits() & ((1 << 23) - 1);
34
35 let bits = InlAwi::zero();
36 let mut res = FP::new(
37 true,
38 bits,
39 ((1isize << 7) - 1 + 23).wrapping_sub(exponent as isize),
40 )
41 .unwrap();
42 if exponent == 0 {
43 if mantissa != 0 {
44 // denormal
45 let mut number = mantissa;
46 if sign {
47 number = number.wrapping_neg();
48 }
49 res.u32_(number);
50 } // else do nothing becuase it is zero
51 } else if exponent != u8::MAX {
52 // add leading 1
53 let mut number = mantissa | (1 << 23);
54 if sign {
55 number = number.wrapping_neg();
56 }
57 res.u32_(number);
58 } // else it is Infinity or NaN which is left as zero
59 res
60 }
61}
62
63impl F64 {
64 /// Translates the IEEE-754 value of `f` to an [F64](crate::fp::F64),
65 /// handling subnormal values correctly and casting the values of
66 /// infinities and NaN to zero (with the fixed point always being 1075
67 /// minus the raw exponent).
68 pub fn from_f64(f: f64) -> Self {
69 let exponent = ((f.to_bits() >> 52) & ((1 << 11) - 1)) as u16;
70 let sign = (f.to_bits() >> 63) != 0;
71 let mantissa = f.to_bits() & ((1 << 52) - 1);
72
73 let bits = InlAwi::zero();
74 let mut res = FP::new(
75 true,
76 bits,
77 ((1isize << 10) - 1 + 52).wrapping_sub(exponent as isize),
78 )
79 .unwrap();
80 if exponent == 0 {
81 if mantissa != 0 {
82 // denormal
83 let mut number = mantissa;
84 if sign {
85 number = number.wrapping_neg();
86 }
87 res.u64_(number);
88 } // else do nothing becuase it is zero
89 } else if exponent != ((1 << 11) - 1) {
90 // add leading 1
91 let mut number = mantissa | (1 << 52);
92 if sign {
93 number = number.wrapping_neg();
94 }
95 res.u64_(number);
96 } // else it is Infinity or NaN which is left as zero
97 res
98 }
99}
100
101impl<B: BorrowMut<Bits>> FP<B> {
102 /// Floating-assigns `FP::from_f32(f)` to `this`. Note that this modifies
103 /// `this.fp` according to [floating_](FP::floating_).
104 pub fn f32_(this: &mut Self, f: f32) {
105 FP::floating_(this, &mut FP::from_f32(f)).unwrap()
106 }
107
108 /// The same as [f32_](FP::f32_) except `None` is returned if `f` is an
109 /// infinity or NaN
110 pub fn checked_f32_(this: &mut Self, f: f32) -> Option<()> {
111 let exponent = ((f.to_bits() >> 23) & ((1 << 8) - 1)) as u8;
112 if exponent == u8::MAX {
113 return None
114 }
115 FP::f32_(this, f);
116 Some(())
117 }
118
119 /// Floating-assigns `FP::from_f64(f)` to `this`. Note that this modifies
120 /// `this.fp` according to [floating_](FP::floating_).
121 pub fn f64_(this: &mut Self, f: f64) {
122 FP::floating_(this, &mut FP::from_f64(f)).unwrap()
123 }
124
125 /// The same as [f64_](FP::f64_) except `None` is returned if `f` is an
126 /// infinity or NaN
127 pub fn checked_f64_(this: &mut Self, f: f64) -> Option<()> {
128 let exponent = ((f.to_bits() >> 52) & ((1 << 11) - 1)) as u16;
129 if exponent == ((1 << 11) - 1) {
130 return None
131 }
132 FP::f64_(this, f);
133 Some(())
134 }
135
136 /// Translates `this` to its IEEE-754 32 bit floating point value, using
137 /// truncation rounding. Infinities and NaN are never returned. If the
138 /// significant numerical value would be unrepresentable (i.e. the most
139 /// significant numerical bit is 2^128 or greater), `None` is returned.
140 pub fn try_to_f32(this: &mut Self) -> Option<f32> {
141 if this.is_zero() {
142 return Some(0.0)
143 }
144 let sign = this.is_negative();
145 // note: reinterpret as unsigned
146 this.neg_(sign);
147 let lz = this.lz();
148 // most significant numerical bit
149 let msnb = FP::rel_sb(this).1.wrapping_sub(lz as isize);
150 let res = if msnb > 127 {
151 // overflow
152 None
153 } else if msnb < (-128 - 23) {
154 // less than what subnormals can represent
155 Some(0.0)
156 } else {
157 let mut mantissa = InlAwi::from_u32(0);
158 let sig = this.sig();
159 if msnb <= -127 {
160 // subnormal
161 let (from, width) = if sig >= 23 {
162 (sig.wrapping_sub(23), 23)
163 } else {
164 (0, sig)
165 };
166 mantissa.field_from(this, from, width).unwrap();
167 Some(f32::from_bits(mantissa.to_u32() | ((sign as u32) << 31)))
168 } else {
169 // normal
170 let (to, from, width) = if sig >= 24 {
171 (0, sig.wrapping_sub(24), 23)
172 } else {
173 (24usize.wrapping_sub(sig), 0, sig.wrapping_sub(1))
174 };
175 mantissa.field(to, this, from, width).unwrap();
176 let exponent = (msnb as u32).wrapping_add(127);
177 Some(f32::from_bits(
178 mantissa.to_u32() | (exponent << 23) | ((sign as u32) << 31),
179 ))
180 }
181 };
182 this.neg_(sign);
183 res
184 }
185
186 /// Translates `this` to its IEEE-754 64 bit floating point value, using
187 /// truncation rounding. Infinities and NaN are never returned. If the
188 /// significant numerical value would be unrepresentable (i.e. the most
189 /// significant numerical bit is 2^1024 or greater), `None` is returned.
190 pub fn try_to_f64(this: &mut Self) -> Option<f64> {
191 if this.is_zero() {
192 return Some(0.0)
193 }
194 let sign = this.is_negative();
195 // note: reinterpret as unsigned
196 this.neg_(sign);
197 let lz = this.lz();
198 // most significant numerical bit
199 let msnb = FP::rel_sb(this).1.wrapping_sub(lz as isize);
200 let res = if msnb > 1023 {
201 // overflow
202 None
203 } else if msnb < (-1024 - 52) {
204 // less than what subnormals can represent
205 Some(0.0)
206 } else {
207 let mut mantissa = InlAwi::from_u64(0);
208 let sig = this.sig();
209 if msnb <= -1023 {
210 // subnormal
211 let (from, width) = if sig >= 52 {
212 (sig.wrapping_sub(52), 52)
213 } else {
214 (0, sig)
215 };
216 mantissa.field_from(this, from, width).unwrap();
217 Some(f64::from_bits(mantissa.to_u64() | ((sign as u64) << 63)))
218 } else {
219 // normal
220 let (to, from, width) = if sig >= 53 {
221 (0, sig.wrapping_sub(53), 52)
222 } else {
223 (53usize.wrapping_sub(sig), 0, sig.wrapping_sub(1))
224 };
225 mantissa.field(to, this, from, width).unwrap();
226 let exponent = (msnb as u64).wrapping_add(1023);
227 Some(f64::from_bits(
228 mantissa.to_u64() | (exponent << 52) | ((sign as u64) << 63),
229 ))
230 }
231 };
232 this.neg_(sign);
233 res
234 }
235}