softposit/p8e0/
convert.rs1use super::P8E0;
2use crate::{u32_with_sign, u64_with_sign, u8_with_sign};
3use core::{f32, f64, mem::transmute};
4
5crate::macros::impl_convert!(P8E0);
6
7impl P8E0 {
8 pub const fn from_f32(float: f32) -> Self {
9 use crate::RawFloat;
10 let ui: u32 = unsafe { transmute(float) };
11
12 let sign = (ui & f32::SIGN_MASK) != 0;
13
14 let uip = ui & !f32::SIGN_MASK;
15 if uip == 0 {
17 Self::ZERO
18 } else if uip >= 0x_7f80_0000 {
19 Self::NAR
20 } else if uip >= 0x_4280_0000 {
21 if !sign {
23 Self::MAX
24 } else {
25 Self::MIN
26 }
27 } else if uip == 0x_3f80_0000 {
28 if !sign {
30 Self::ONE
31 } else {
32 Self::ONE.neg()
33 }
34 } else if uip <= 0x_3c80_0000 {
35 if !sign {
37 Self::MIN_POSITIVE
38 } else {
39 Self::MIN_POSITIVE.neg()
40 }
41 } else {
42 Self::from_bits(crate::convert::convert_float!(P8E0, f32, ui))
43 }
44 }
45
46 pub const fn from_f64(float: f64) -> Self {
47 use crate::RawFloat;
48 let ui: u64 = unsafe { transmute(float) };
49
50 let sign = (ui & f64::SIGN_MASK) != 0;
51
52 let uip = ui & !f64::SIGN_MASK;
53 if uip == 0 {
55 Self::ZERO
56 } else if uip >= 0x_7ff0_0000_0000_0000 {
57 Self::NAR
58 } else if uip >= 0x_4050_0000_0000_0000 {
59 if !sign {
61 Self::MAX
62 } else {
63 Self::MIN
64 }
65 } else if uip == 0x_3ff0_0000_0000_0000 {
66 if !sign {
68 Self::ONE
69 } else {
70 Self::ONE.neg()
71 }
72 } else if uip <= 0x_3f90_0000_0000_0000 {
73 if !sign {
75 Self::MIN_POSITIVE
76 } else {
77 Self::MIN_POSITIVE.neg()
78 }
79 } else {
80 Self::from_bits(crate::convert::convert_float!(P8E0, f64, ui))
81 }
82 }
83
84 pub const fn to_f32(self) -> f32 {
85 let mut ui_a = self.to_bits();
86
87 if self.is_zero() {
88 0.
89 } else if self.is_nar() {
90 f32::NAN
91 } else {
92 let sign_a = ui_a & P8E0::SIGN_MASK;
93 if sign_a != 0 {
94 ui_a = ui_a.wrapping_neg();
95 }
96 let (k_a, tmp) = P8E0::separate_bits_tmp(ui_a);
97
98 let frac_a = ((tmp << 1) as u32) << 15;
99 let exp_a = (k_a as u32).wrapping_add(127) << 23;
100
101 unsafe { transmute(exp_a + frac_a + ((sign_a as u32) << 24)) }
102 }
103 }
104
105 pub const fn to_f64(self) -> f64 {
106 let mut ui_a = self.to_bits();
107
108 if self.is_zero() {
109 0.
110 } else if self.is_nar() {
111 f64::NAN
112 } else {
113 let sign_a = ui_a & P8E0::SIGN_MASK;
114 if sign_a != 0 {
115 ui_a = ui_a.wrapping_neg();
116 }
117 let (k_a, tmp) = P8E0::separate_bits_tmp(ui_a);
118
119 let frac_a = ((tmp << 1) as u64) << 44;
120 let exp_a = (k_a as u64).wrapping_add(1023) << 52;
121
122 unsafe { transmute(exp_a + frac_a + ((sign_a as u64) << 56)) }
123 }
124 }
125
126 #[inline]
127 pub const fn to_i32(self) -> i32 {
128 let mut ui_a = self.to_bits();
129 if ui_a == 0x80 {
131 return i32::min_value();
132 }
133
134 let sign = ui_a > 0x80; if sign {
136 ui_a = ui_a.wrapping_neg(); }
138 let i_z = convert_p8bits_to_u32(ui_a);
139
140 u32_with_sign(i_z, sign) as i32
141 }
142
143 #[inline]
144 pub const fn to_u32(self) -> u32 {
145 let ui_a = self.to_bits();
146
147 if ui_a >= 0x80 {
148 return 0; }
150 convert_p8bits_to_u32(ui_a)
151 }
152
153 #[inline]
154 pub const fn from_u32(a: u32) -> Self {
155 Self::from_bits(convert_u32_to_p8bits(a))
156 }
157
158 #[inline]
159 pub const fn from_i32(mut i_a: i32) -> Self {
160 if i_a < -48 {
161 return Self::MIN;
163 }
164
165 let sign = i_a.is_negative();
166 if sign {
167 i_a = -i_a;
168 }
169 Self::from_bits(u8_with_sign(convert_u32_to_p8bits(i_a as u32), sign))
170 }
171
172 #[inline]
173 pub const fn to_i64(self) -> i64 {
174 let mut ui_a = self.to_bits();
175
176 if ui_a == 0x80 {
178 return i64::min_value();
179 }
180
181 let sign = (ui_a & 0x_80) != 0;
182 if sign {
183 ui_a = ui_a.wrapping_neg();
184 }
185
186 let i_z = convert_p8bits_to_u64(ui_a);
187
188 u64_with_sign(i_z, sign) as i64
189 }
190
191 #[inline]
192 pub const fn to_u64(self) -> u64 {
193 let ui_a = self.to_bits();
194
195 if ui_a >= 0x80 {
196 return 0; }
198 convert_p8bits_to_u64(ui_a)
199 }
200
201 #[inline]
202 pub const fn from_u64(a: u64) -> Self {
203 Self::from_bits(convert_u64_to_p8bits(a))
204 }
205
206 pub const fn from_i64(mut i_a: i64) -> Self {
207 if i_a < -48 {
208 return Self::MIN;
210 }
211
212 let sign = i_a.is_negative();
213 if sign {
214 i_a = -i_a;
215 }
216 Self::from_bits(u8_with_sign(convert_u64_to_p8bits(i_a as u64), sign))
217 }
218}
219
220const fn convert_p8bits_to_u32(ui_a: u8) -> u32 {
221 if ui_a <= 0x20 {
222 0
224 } else if ui_a < 0x50 {
225 1
227 } else {
228 let (scale, bits) = P8E0::calculate_scale(ui_a);
229
230 let mut i_z = ((bits as u32) | 0x40) << 24; let mut mask = 0x4000_0000_u32 >> scale; let bit_last = (i_z & mask) != 0; mask >>= 1;
236 let mut tmp = i_z & mask;
237 let bit_n_plus_one = tmp != 0; i_z ^= tmp; tmp = i_z & (mask - 1); i_z ^= tmp; if bit_n_plus_one {
243 if (bit_last as u32 | tmp) != 0 {
245 i_z += mask << 1;
246 }
247 }
248 i_z >> (30 - scale) }
250}
251
252const fn convert_p8bits_to_u64(ui_a: u8) -> u64 {
253 if ui_a <= 0x20 {
254 0
256 } else if ui_a < 0x50 {
257 1
259 } else {
260 let (scale, bits) = P8E0::calculate_scale(ui_a);
261
262 let mut i_z = ((bits as u64) | 0x40) << 55; let mut mask = 0x2000_0000_0000_0000_u64 >> scale; let bit_last = (i_z & mask) != 0; mask >>= 1;
268 let mut tmp = i_z & mask;
269 let bit_n_plus_one = tmp != 0; i_z ^= tmp; tmp = i_z & (mask - 1); i_z ^= tmp; if bit_n_plus_one {
275 if (bit_last as u64 | tmp) != 0 {
277 i_z += mask << 1;
278 }
279 }
280 i_z >> (61 - scale) }
282}
283
284const fn convert_u32_to_p8bits(a: u32) -> u8 {
285 if a > 48 {
286 0x7F
287 } else if a < 2 {
288 (a << 6) as u8
289 } else {
290 let mut log2 = 6_i8; let mut mask = 0x40_u32;
292 let mut frac_a = a;
293 while (frac_a & mask) == 0 {
294 log2 -= 1;
295 frac_a <<= 1;
296 }
297
298 let k = log2;
299
300 frac_a ^= mask;
301
302 let mut ui_a: u8 = (0x7F ^ (0x3F >> k)) | (frac_a >> (k + 1)) as u8;
303
304 mask = 0x1 << k; if ((mask & frac_a) != 0) && ((((mask - 1) & frac_a) | ((mask << 1) & frac_a)) != 0) {
306 ui_a += 1;
307 }
308 ui_a
309 }
310}
311
312const fn convert_u64_to_p8bits(a: u64) -> u8 {
313 if a > 48 {
314 0x7F
315 } else if a < 2 {
316 (a << 6) as u8
317 } else {
318 let mut log2 = 6_i8; let mut mask = 0x40_u64;
320 let mut frac_a = a;
321 while (frac_a & mask) == 0 {
322 log2 -= 1;
323 frac_a <<= 1;
324 }
325
326 let k = log2;
327
328 frac_a ^= mask;
329
330 let mut ui_a: u8 = (0x7F ^ (0x3F >> k)) | (frac_a >> (k + 1)) as u8;
331
332 mask = 0x1 << k; if ((mask & frac_a) != 0) && ((((mask - 1) & frac_a) | ((mask << 1) & frac_a)) != 0) {
334 ui_a += 1;
335 }
336 ui_a
337 }
338}
339
340#[test]
341fn convert_p8_f64() {
342 for n in -0x_80_i8..0x_7f {
343 let p = P8E0::new(n);
344 let f = f64::from(p);
345 assert_eq!(p, P8E0::from(f));
346 }
347}
348
349#[test]
350fn convert_p8_f32() {
351 for n in -0x_80_i8..0x_7f {
352 let p = P8E0::new(n);
353 let f = f32::from(p);
354 assert_eq!(p, P8E0::from(f));
355 }
356}
357
358#[test]
359fn convert_f64_p8_rand() {
360 use rand::Rng;
361 let mut rng = rand::thread_rng();
362 for _ in 0..crate::NTESTS8 {
363 let f: f64 = rng.gen();
364 let _p = P8E0::from(f);
365 }
366}
367
368#[test]
369fn convert_f32_p8_rand() {
370 use rand::Rng;
371 let mut rng = rand::thread_rng();
372 for _ in 0..crate::NTESTS8 {
373 let f: f32 = rng.gen();
374 let _p = P8E0::from(f);
375 }
376}