softposit/pxe1/
convert.rs

1use super::PxE1;
2use crate::{u32_with_sign, u64_with_sign};
3use core::f64;
4
5impl<const N: u32> From<PxE1<{ N }>> for f32 {
6    #[inline]
7    fn from(a: PxE1<{ N }>) -> Self {
8        a.to_f32()
9    }
10}
11
12impl<const N: u32> From<PxE1<{ N }>> for f64 {
13    #[inline]
14    fn from(p_a: PxE1<{ N }>) -> Self {
15        p_a.to_f64()
16    }
17}
18
19impl<const N: u32> From<f32> for PxE1<{ N }> {
20    #[inline]
21    fn from(float: f32) -> Self {
22        Self::from_f32(float)
23    }
24}
25
26impl<const N: u32> From<f64> for PxE1<{ N }> {
27    #[inline]
28    fn from(float: f64) -> Self {
29        Self::from_f64(float)
30    }
31}
32
33impl<const N: u32> From<PxE1<{ N }>> for i32 {
34    #[inline]
35    fn from(p_a: PxE1<{ N }>) -> Self {
36        p_a.to_i32()
37    }
38}
39
40impl<const N: u32> From<PxE1<{ N }>> for u32 {
41    #[inline]
42    fn from(p_a: PxE1<{ N }>) -> Self {
43        p_a.to_u32()
44    }
45}
46
47impl<const N: u32> From<PxE1<{ N }>> for i64 {
48    #[inline]
49    fn from(p_a: PxE1<{ N }>) -> Self {
50        p_a.to_i64()
51    }
52}
53
54impl<const N: u32> From<PxE1<{ N }>> for u64 {
55    #[inline]
56    fn from(p_a: PxE1<{ N }>) -> Self {
57        p_a.to_u64()
58    }
59}
60
61impl<const N: u32> From<u64> for PxE1<{ N }> {
62    #[inline]
63    fn from(a: u64) -> Self {
64        Self::from_u64(a)
65    }
66}
67
68impl<const N: u32> From<i64> for PxE1<{ N }> {
69    #[inline]
70    fn from(a: i64) -> Self {
71        Self::from_i64(a)
72    }
73}
74
75impl<const N: u32> From<u32> for PxE1<{ N }> {
76    #[inline]
77    fn from(a: u32) -> Self {
78        Self::from_u32(a)
79    }
80}
81
82impl<const N: u32> From<i32> for PxE1<{ N }> {
83    #[inline]
84    fn from(a: i32) -> Self {
85        Self::from_i32(a)
86    }
87}
88
89impl<const N: u32> PxE1<{ N }> {
90    #[inline]
91    pub fn to_f32(self) -> f32 {
92        self.to_f64() as f32
93    }
94
95    pub fn to_f64(self) -> f64 {
96        let mut ui_a = self.to_bits();
97
98        if self.is_zero() {
99            0.
100        } else if self.is_nar() {
101            f64::NAN
102        } else {
103            let sign_a = ui_a & 0x_8000_0000;
104            if sign_a != 0 {
105                ui_a = ui_a.wrapping_neg();
106            }
107            let (k_a, tmp) = PxE1::<{ N }>::separate_bits_tmp(ui_a);
108
109            let frac_a = ((tmp << 2) as u64) << 20;
110            let exp_a = (((k_a as u64) << 1) + ((tmp >> 30) as u64)).wrapping_add(1023) << 52;
111
112            f64::from_bits(exp_a + frac_a + ((sign_a as u64) << 32))
113        }
114    }
115
116    #[inline]
117    pub fn from_f32(float: f32) -> Self {
118        Self::from_f64(float as f64)
119    }
120
121    #[allow(clippy::cognitive_complexity)]
122    pub fn from_f64(mut float: f64) -> Self {
123        let mut reg: u32;
124        let mut frac = 0_u32;
125        let mut exp = 0_i32;
126        let mut bit_n_plus_one = false;
127        let mut bits_more = false;
128
129        if float == 0. {
130            return Self::ZERO;
131        } else if !float.is_finite() {
132            return Self::NAR;
133        }
134
135        let sign = float < 0.;
136
137        let u_z: u32 = if float == 1. {
138            0x4000_0000
139        } else if float == -1. {
140            0xC000_0000
141        } else if !(-1. ..=1.).contains(&float) {
142            if sign {
143                //Make negative numbers positive for easier computation
144                float = -float;
145            }
146
147            let reg_s = true;
148            reg = 1; //because k = m-1; so need to add back 1
149                     // minpos
150            if (N == 2) && (float <= 8.673_617_379_884_035_e-19) {
151                1
152            } else {
153                //regime
154                while float >= 4. {
155                    float *= 0.25; // float/=4;
156                    reg += 1;
157                }
158                if float >= 2. {
159                    float *= 0.5;
160                    exp += 1;
161                }
162                let frac_length = (N - 3) as isize - (reg as isize);
163                if frac_length < 0 {
164                    if reg == N - 2 {
165                        bit_n_plus_one = exp != 0;
166                        exp = 0;
167                    }
168                    if float > 1. {
169                        bits_more = true;
170                    }
171                } else {
172                    frac = crate::convert_fraction_p32(
173                        float,
174                        frac_length as u16,
175                        &mut bit_n_plus_one,
176                        &mut bits_more,
177                    );
178                }
179
180                if (reg == 30) && (frac > 0) {
181                    bits_more = true;
182                    frac = 0;
183                }
184
185                u32_with_sign(
186                    if reg > (N - 2) {
187                        if reg_s {
188                            0x_7FFF_FFFF & Self::mask()
189                        } else {
190                            0x1 << (32 - N)
191                        }
192                    } else {
193                        //rounding off fraction bits
194
195                        let regime = if reg_s { ((1 << reg) - 1) << 1 } else { 1_u32 };
196
197                        let mut u_z = (regime << (30 - reg))
198                            + ((exp as u32) << (29 - reg))
199                            + ((frac << (32 - N)) as u32);
200                        //minpos
201                        if (u_z == 0) && (frac > 0) {
202                            u_z = 0x1 << (32 - N);
203                        }
204                        if bit_n_plus_one {
205                            u_z += (((u_z >> (32 - N)) & 0x1) | (bits_more as u32)) << (32 - N);
206                        }
207                        u_z
208                    },
209                    sign,
210                )
211            }
212        } else if (float < 1.) || (float > -1.) {
213            if sign {
214                //Make negative numbers positive for easier computation
215                float = -float;
216            }
217
218            let reg_s = false;
219            reg = 0;
220
221            //regime
222            while float < 1. {
223                float *= 4.;
224                reg += 1;
225            }
226
227            if float >= 2. {
228                float *= 0.5;
229                exp += 1;
230            }
231
232            let frac_length = (N - 3) as isize - (reg as isize);
233            if frac_length < 0 {
234                if reg == N - 2 {
235                    bit_n_plus_one = exp != 0;
236                    exp = 0;
237                }
238
239                if float > 1. {
240                    bits_more = true;
241                }
242            } else {
243                frac = crate::convert_fraction_p32(
244                    float,
245                    frac_length as u16,
246                    &mut bit_n_plus_one,
247                    &mut bits_more,
248                );
249            }
250
251            if (reg == 30) && (frac > 0) {
252                bits_more = true;
253                frac = 0;
254            }
255
256            u32_with_sign(
257                if reg > (N - 2) {
258                    if reg_s {
259                        0x_7FFF_FFFF & Self::mask()
260                    } else {
261                        0x1 << (32 - N)
262                    }
263                } else {
264                    //rounding off fraction bits
265
266                    let regime = if reg_s { ((1 << reg) - 1) << 1 } else { 1_u32 };
267
268                    let mut u_z = (regime << (30 - reg))
269                        + ((exp as u32) << (29 - reg))
270                        + ((frac << (32 - N)) as u32);
271                    //minpos
272                    if (u_z == 0) && (frac > 0) {
273                        u_z = 0x1 << (32 - N);
274                    }
275
276                    if bit_n_plus_one {
277                        u_z += (((u_z >> (32 - N)) & 0x1) | (bits_more as u32)) << (32 - N);
278                    }
279                    u_z
280                },
281                sign,
282            )
283        } else {
284            //NaR - for NaN, INF and all other combinations
285            0x8000_0000
286        };
287        Self::from_bits(u_z)
288    }
289
290    pub const fn to_i32(self) -> i32 {
291        //NaR
292        if self.is_nar() {
293            return i32::min_value();
294        }
295
296        let mut ui_a = self.to_bits();
297
298        let sign = ui_a > 0x_8000_0000; // sign is True if pA > NaR.
299
300        if sign {
301            ui_a = ui_a.wrapping_neg(); // A is now |A|.
302        }
303
304        let i_z = convert_px1bits_to_u32(ui_a);
305        u32_with_sign(i_z, sign) as i32
306    }
307
308    pub const fn to_u32(self) -> u32 {
309        let ui_a = self.to_bits();
310        //NaR
311        if ui_a >= 0x_8000_0000 {
312            0
313        } else {
314            convert_px1bits_to_u32(ui_a)
315        }
316    }
317
318    pub const fn to_i64(self) -> i64 {
319        //NaR
320        if self.is_nar() {
321            return i64::min_value();
322        }
323
324        let mut ui_a = self.to_bits();
325
326        let sign = ui_a > 0x_8000_0000; // sign is True if pA > NaR.
327
328        if sign {
329            ui_a = ui_a.wrapping_neg(); // A is now |A|.
330        }
331
332        let i_z = convert_px1bits_to_u64(ui_a);
333
334        u64_with_sign(i_z, sign) as i64
335    }
336
337    pub const fn to_u64(self) -> u64 {
338        let ui_a = self.to_bits();
339        //NaR
340        if ui_a >= 0x_8000_0000 {
341            0
342        } else {
343            convert_px1bits_to_u64(ui_a)
344        }
345    }
346
347    pub const fn from_u64(a: u64) -> Self {
348        let ui_a = if a == 0x_8000_0000_0000_0000 {
349            0x_8000_0000
350        } else if N == 2 {
351            if a > 0 {
352                0x_4000_0000
353            } else {
354                0
355            }
356        } else if a > 0x_8000_0000_0000_0000 {
357            //576460752303423488 -> wrong number need to change
358            0x_7FFF_FFFF & ((0x_8000_0000_u64 >> (N - 1)) as u32) // 1152921504606847000
359        } else {
360            convert_u64_to_px1bits::<{ N }>(a)
361        };
362        Self::from_bits(ui_a)
363    }
364
365    pub const fn from_i64(_a: i64) -> Self {
366        todo!()
367    }
368
369    pub const fn from_i32(a: i32) -> Self {
370        let mut log2 = 31_i8; //length of bit (e.g. 2147418111) in int (32 but because we have only 32 bits, so one bit off to accommodate that fact)
371
372        let mut ui_a = 0u32;
373        let mask = 0x80000000_u32;
374
375        let sign = a >> 31 != 0;
376        let a = if sign { -a as u32 } else { a as u32 };
377
378        //NaR
379        if a == 0x80000000 {
380            ui_a = 0x80000000;
381        } else if N == 2 {
382            if a > 0 {
383                ui_a = 0x40000000;
384            }
385        } else if a > 2147418111 {
386            ui_a = 0x7FFF9FFF; // 2147483648
387                               //if (x<12)  ui_a&=((int32_t)0x80000000>>(x-1));
388        } else if a < 0x2 {
389            ui_a = (a << 30) as u32;
390        } else {
391            let mut frac_a = a;
392            while (frac_a & mask) == 0 {
393                log2 -= 1;
394                frac_a <<= 1;
395            }
396            let k = (log2 >> 1) as u32;
397            let exp_a = ((log2 & 0x1) as u32) << (28 - k);
398            frac_a ^= mask;
399
400            if k >= (N - 2) {
401                //maxpos
402                ui_a = 0x7FFFFFFF & Self::mask();
403            } else if k == (N - 3) {
404                //bitNPlusOne-> first exp bit //bitLast is zero
405                ui_a = 0x7FFFFFFF ^ (0x3FFFFFFF >> k);
406                if (exp_a & 0x2) != 0 && ((exp_a & 0x1) | frac_a) != 0 {
407                    //bitNPlusOne //bitsMore
408                    ui_a |= 0x80000000_u32 >> (N - 1);
409                }
410            } else if k == (N - 4) {
411                ui_a = (0x7FFFFFFF ^ (0x3FFFFFFF >> k)) | ((exp_a & 0x2) << (27 - k));
412                if exp_a & 0x1 != 0 && (((0x80000000_u32 >> (N - 1)) & ui_a) | frac_a) != 0 {
413                    ui_a += 0x80000000_u32 >> (N - 1);
414                }
415            } else if k == (N - 5) {
416                ui_a = (0x7FFFFFFF ^ (0x3FFFFFFF >> k)) | (exp_a << (27 - k));
417                let mask = 0x8 << (k - N);
418                if (mask & frac_a) != 0 {
419                    //bitNPlusOne
420                    if (((mask - 1) & frac_a) | (exp_a & 0x1)) != 0 {
421                        ui_a += 0x80000000_u32 >> (N - 1);
422                    }
423                }
424            } else {
425                ui_a =
426                    ((0x7FFFFFFFu32 ^ (0x3FFFFFFF >> k)) | (exp_a << (27 - k)) | frac_a >> (k + 4))
427                        & Self::mask();
428                let mask = 0x8 << (k - N); //bitNPlusOne
429                if (mask & frac_a) != 0 && (((mask - 1) & frac_a) | ((mask << 1) & frac_a)) != 0 {
430                    ui_a += 0x80000000_u32 >> (N - 1);
431                }
432            }
433        }
434        Self::from_bits(if sign { ui_a.wrapping_neg() } else { ui_a })
435    }
436
437    pub const fn from_u32(_a: u32) -> Self {
438        todo!()
439    }
440}
441
442#[inline]
443const fn calculate_scale(mut bits: u32) -> (u32, u32) {
444    // Decode the posit, left-justifying as we go.
445    let mut scale = 0_u32;
446
447    bits -= 0x_4000_0000; // Strip off first regime bit (which is a 1).
448    while (0x_2000_0000 & bits) != 0 {
449        // Increment scale by 2 for each regime sign bit.
450        scale += 2; // Regime sign bit is always 1 in this range.
451        bits = (bits - 0x_2000_0000) << 1; // Remove the bit; line up the next regime bit.
452    }
453    bits <<= 1; // Skip over termination bit, which is 0.
454    if (0x_2000_0000 & bits) != 0 {
455        scale += 1;
456    } // If exponent is 1, increment the scale.
457
458    (scale, bits)
459}
460
461const fn convert_px1bits_to_u32(ui_a: u32) -> u32 {
462    if ui_a <= 0x_3000_0000 {
463        // 0 <= |pA| <= 1/2 rounds to zero.
464        0
465    } else if ui_a < 0x_4800_0000 {
466        // 1/2 < x < 3/2 rounds to 1.
467        1
468    } else if ui_a <= 0x_5400_0000 {
469        // 3/2 <= x <= 5/2 rounds to 2.
470        2
471    } else if ui_a > 0x_7FFF_BFFF {
472        //4294836223
473        4_294_967_295
474    } else {
475        let (scale, bits) = calculate_scale(ui_a);
476
477        let mut i_z64 = ((bits | 0x_2000_0000) as u64) << 33; // Left-justify fraction in 64-bit result (one left bit padding)
478
479        let mut mask = 0x4000_0000_0000_0000_u64 >> scale; // Point to the last bit of the integer part.
480
481        let bit_last = i_z64 & mask; // Extract the bit, without shifting it.
482        mask >>= 1;
483        let mut tmp = i_z64 & mask;
484        let bit_n_plus_one = tmp != 0; // "True" if nonzero.
485        i_z64 ^= tmp; // Erase the bit, if it was set.
486        tmp = i_z64 & (mask - 1); // tmp has any remaining bits. // This is bits_more
487        i_z64 ^= tmp; // Erase those bits, if any were set.
488
489        if bit_n_plus_one {
490            // logic for round to nearest, tie to even
491            if (bit_last | tmp) != 0 {
492                i_z64 += mask << 1;
493            }
494        }
495
496        (i_z64 >> (62 - scale)) as u32 // Right-justify the integer.
497    }
498}
499
500const fn convert_px1bits_to_u64(ui_a: u32) -> u64 {
501    if ui_a <= 0x_3000_0000 {
502        // 0 <= |pA| <= 1/2 rounds to zero.
503        0
504    } else if ui_a < 0x_4800_0000 {
505        // 1/2 < x < 3/2 rounds to 1.
506        1
507    } else if ui_a <= 0x_5400_0000 {
508        // 3/2 <= x <= 5/2 rounds to 2.
509        2
510    } else {
511        let (scale, bits) = calculate_scale(ui_a);
512
513        let mut i_z = ((bits | 0x_2000_0000) as u64) << 33; // Left-justify fraction in 64-bit result (one left bit padding)
514        let mut mask = 0x_4000_0000_0000_0000 >> scale; // Point to the last bit of the integer part.
515
516        let bit_last = i_z & mask; // Extract the bit, without shifting it.
517        mask >>= 1;
518        let mut tmp = i_z & mask;
519        let bit_n_plus_one = tmp != 0; // "True" if nonzero.
520        i_z ^= tmp; // Erase the bit, if it was set.
521        tmp = i_z & (mask - 1); // tmp has any remaining bits. // This is bits_more
522        i_z ^= tmp; // Erase those bits, if any were set.
523
524        if bit_n_plus_one {
525            // logic for round to nearest, tie to even
526            if (bit_last | tmp) != 0 {
527                i_z += mask << 1;
528            }
529        }
530
531        i_z >> (62 - scale) // Right-justify the integer.
532    }
533}
534
535const fn convert_u64_to_px1bits<const N: u32>(a: u64) -> u32 {
536    let mut log2 = 63_i8; //60;//length of bit (e.g. 576460752303423488 = 2^59) in int (64 but because we have only 64 bits, so one bit off to accommodate that fact)
537    let mut mask = 0x_8000_0000_0000_0000_u64;
538    if a < 0x2 {
539        (a as u32) << 30
540    } else {
541        let mut frac64_a = a;
542        while (frac64_a & mask) == 0 {
543            log2 -= 1;
544            frac64_a <<= 1;
545        }
546
547        let k = (log2 >> 1) as u32;
548
549        let exp_a = (log2 & 0x1) as u32;
550        frac64_a ^= mask;
551        frac64_a <<= 1;
552
553        let mut ui_a: u32;
554        if k >= (N - 2) {
555            //maxpos
556            ui_a = 0x_7FFF_FFFF & PxE1::<{ N }>::mask();
557        } else if k == (N - 3) {
558            //bitNPlusOne-> exp bit //bitLast is zero
559            ui_a = 0x_7FFF_FFFF ^ (0x_3FFF_FFFF >> k);
560            if ((exp_a & 0x1) != 0) && (frac64_a != 0) {
561                //bitNPlusOne //bitsMore
562                ui_a |= 0x_8000_0000_u32 >> (N - 1);
563            }
564        } else if k == (N - 4) {
565            //bitLast = regime terminating bit
566            ui_a = (0x_7FFF_FFFF ^ (0x_3FFF_FFFF >> k)) | (exp_a << (28 - k));
567            mask = 0x_0008_0000_0000_u64 << (k + 32 - N);
568            if (mask & frac64_a) != 0 {
569                //bitNPlusOne
570                if (((mask - 1) & frac64_a) | ((exp_a & 0x1) as u64)) != 0 {
571                    ui_a += 0x_8000_0000_u32 >> (N - 1);
572                }
573            }
574        } else {
575            ui_a = (0x_7FFF_FFFF ^ (0x_3FFF_FFFF >> k))
576                | (exp_a << (28 - k))
577                | (((frac64_a >> (k + 36)) as u32) & PxE1::<{ N }>::mask());
578            mask = 0x_0008_0000_0000_u64 << (k + 32 - N); //bitNPlusOne position
579            if ((mask & frac64_a) != 0)
580                && ((((mask - 1) & frac64_a) | ((mask << 1) & frac64_a)) != 0)
581            {
582                ui_a += 0x_8000_0000_u32 >> (N - 1);
583            }
584        }
585        ui_a
586    }
587}