Skip to main content

amplify_num/
posit.rs

1// SPDX-License-Identifier: Apache-2.0
2//
3// Written in 2022 by Yudai Kiyofuji <own7000hr@gmail.com>
4//
5// Licensed under the Apache License, Version 2.0 (the "License"); you may not
6// use this file except in compliance with the License. You may obtain a copy of
7// the License at <http://www.apache.org/licenses/LICENSE-2.0>
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14
15use crate::error::PositDecodeError;
16use crate::{u256, u512, u1024};
17
18macro_rules! construct_posit {
19    (
20        $name:ident,
21        $bits:expr,
22        $es:expr,
23        $internal:ident,
24        $zeros:expr,
25        $ones:expr,
26        $nar:expr,
27        $guard:ident,
28        $guard_zero:expr,
29        $guard_max:expr,
30        $to:ident,
31        $into:ident
32    ) => {
33        #[derive(Copy, Clone, PartialEq, Eq, Hash, Default)]
34        pub struct $name($internal);
35
36        impl $name {
37            pub const ZERO: $name = $name($zeros);
38            pub const NAR: $name = $name($nar);
39
40            #[inline]
41            #[allow(clippy::wrong_self_convention)]
42            #[deprecated(since = "1.5.3", note = "use `into`")]
43            pub const fn $to(&self) -> $internal { self.0 }
44
45            #[inline]
46            pub const fn $into(self) -> $internal { self.0 }
47
48            #[inline]
49            pub fn is_nar(&self) -> bool { self == &Self::NAR }
50
51            #[inline]
52            pub fn is_zero(&self) -> bool { self.0 == $zeros }
53
54            #[inline]
55            pub fn is_negative(&self) -> bool {
56                !self.is_nar() && (self.0 & Self::NAR.0 == Self::NAR.0)
57            }
58
59            #[inline]
60            pub fn is_positive(&self) -> bool {
61                !self.is_nar() && !self.is_negative() && !self.is_zero()
62            }
63
64            #[inline]
65            pub fn abs(self) -> Self {
66                match self.is_negative() {
67                    true => -self,
68                    false => self,
69                }
70            }
71
72            fn regime<T: Into<i32>>(exp: T) -> (i16, $internal) {
73                let exp = exp.into();
74                let regime = exp >> $es;
75                (regime as i16, $internal::from((exp - (regime << $es)) as u8))
76            }
77
78            fn exp(regime: i16, exp: $internal) -> i32 {
79                ((regime as i32) << $es) + exp.to_le_bytes()[0] as i32
80            }
81
82            pub fn from_bits(bits: $internal) -> Self { Self(bits) }
83
84            pub fn decode(&self) -> Result<(bool, i16, $internal, $internal), PositDecodeError> {
85                if self.is_zero() {
86                    return Err(PositDecodeError::Zero);
87                }
88                if self.is_nar() {
89                    return Err(PositDecodeError::NaR);
90                }
91                let sign = self.is_negative();
92                let input = self.abs().0 << 1;
93                let (regime, input) = match ((!input).leading_zeros(), input.leading_zeros()) {
94                    (0, zeros) => {
95                        (-(zeros as i16), input.checked_shl(zeros as u32 + 1).unwrap_or($zeros))
96                    }
97                    (ones, _) => {
98                        ((ones - 1) as i16, input.checked_shl(ones as u32 + 1).unwrap_or($zeros))
99                    }
100                };
101                let exp = input.checked_shr($bits - $es).unwrap_or($zeros);
102                let mantissa = input.checked_shl($es).unwrap_or($zeros);
103                Ok((sign, regime, exp, mantissa))
104            }
105
106            pub fn encode(sign: bool, regime: i16, exp: $internal, mantissa: $internal) -> Self {
107                Self::_encode(sign, regime, $guard::from(exp), $guard::from(mantissa) << $bits)
108            }
109
110            fn _encode(sign: bool, regime: i16, exp: $guard, mantissa: $guard) -> Self {
111                let shl = |x: $guard, shift| x.checked_shl(shift).unwrap_or($guard_zero);
112                let shr = |x: $guard, shift| x.checked_shr(shift).unwrap_or($guard_zero);
113                let mut res = $guard_zero;
114                let len: u32 = (regime.unsigned_abs() + (!regime.is_negative() as u16)).into();
115                let regime_mask = match regime.is_negative() {
116                    true => shr(!($guard_max >> 1), len + 1),
117                    false => ($guard_max ^ shr($guard_max, len)) >> 1,
118                };
119                let mantissa_mask = shr(mantissa, len + $es + 2);
120                let exp_mask = shl(exp, $bits * 2 - len - 2 - $es);
121                res |= regime_mask | exp_mask | mantissa_mask;
122                let (mut high, low) = {
123                    let mut h = [0u8; $bits / 8];
124                    let mut l = [0u8; $bits / 8];
125                    let bytes = res.to_le_bytes();
126                    for i in 0..($bits / 8) {
127                        h[i] = bytes[$bits / 8 + i]
128                    }
129                    for i in 0..($bits / 8) {
130                        l[i] = bytes[i]
131                    }
132                    ($internal::from_le_bytes(h), $internal::from_le_bytes(l))
133                };
134                match (high == ($ones >> 1), low.cmp(&$nar)) {
135                    (true, _) | (_, ::core::cmp::Ordering::Less) => (),
136                    (_, ::core::cmp::Ordering::Greater) => high += !($ones << 1),
137                    (_, ::core::cmp::Ordering::Equal) => high += (high & !($ones << 1)),
138                };
139                Self(if sign { high.wrapping_neg() } else { high })
140            }
141        }
142
143        impl PartialOrd for $name {
144            #[inline]
145            fn partial_cmp(&self, other: &$name) -> Option<::core::cmp::Ordering> {
146                Some(self.cmp(&other))
147            }
148        }
149
150        impl Ord for $name {
151            #[inline]
152            fn cmp(&self, other: &$name) -> ::core::cmp::Ordering {
153                match (self.is_nar(), other.is_nar()) {
154                    (true, true) => return ::core::cmp::Ordering::Equal,
155                    (true, false) => return ::core::cmp::Ordering::Less,
156                    (false, true) => return ::core::cmp::Ordering::Greater,
157                    _ => (),
158                }
159                match (self.is_negative(), other.is_negative()) {
160                    (false, true) => ::core::cmp::Ordering::Greater,
161                    (true, false) => ::core::cmp::Ordering::Less,
162                    _ => self.0.cmp(&other.0),
163                }
164            }
165        }
166
167        impl ::core::ops::Neg for $name {
168            type Output = Self;
169            fn neg(self) -> Self::Output { Self(self.0.wrapping_neg()) }
170        }
171
172        impl<T> ::core::ops::Add<T> for $name
173        where T: Into<$name>
174        {
175            type Output = $name;
176            fn add(self, other: T) -> $name {
177                let other = other.into();
178                let (lhs, rhs, sign) = {
179                    let (l, r) = (self.abs(), other.abs());
180                    match (l > r, self.is_negative(), other.is_negative()) {
181                        (true, true, true) => (l, r, true),
182                        (true, true, false) => (l, r, true),
183                        (true, false, true) => (l, r, false),
184                        (true, false, false) => (l, r, false),
185                        (false, true, true) => (r, l, true),
186                        (false, false, true) => (r, l, true),
187                        (false, true, false) => (r, l, false),
188                        (false, false, false) => (r, l, false),
189                    }
190                };
191                let (lhs, rhs) = match (lhs.decode(), rhs.decode()) {
192                    (Err(PositDecodeError::NaR), _) | (_, Err(PositDecodeError::NaR)) => {
193                        return Self::NAR;
194                    }
195                    (Err(PositDecodeError::Zero), _) => return (if sign { -rhs } else { rhs }),
196                    (_, Err(PositDecodeError::Zero)) => return (if sign { -lhs } else { lhs }),
197                    (Ok(l), Ok(r)) => (l, r),
198                };
199                let is_add = self.is_negative() == other.is_negative();
200                if !is_add && lhs == rhs {
201                    return Self::ZERO;
202                }
203                let exp_lhs = Self::exp(lhs.1, lhs.2);
204                let exp_rhs = Self::exp(rhs.1, rhs.2);
205                let shift = (exp_lhs - exp_rhs) as u32;
206                let mantissa_lhs = ($guard::from(lhs.3) << ($bits - 2)) | (!($guard_max >> 1) >> 1);
207                let mantissa_rhs = (($guard::from(rhs.3) << ($bits - 2)) |
208                    (!($guard_max >> 1) >> 1))
209                    .checked_shr(shift)
210                    .unwrap_or($guard_zero);
211                let mantissa = match self.is_negative() == other.is_negative() {
212                    true => mantissa_lhs + mantissa_rhs,
213                    false => mantissa_lhs - mantissa_rhs,
214                };
215                let leading_zeros = mantissa.leading_zeros();
216                let scaling_factor = 1 - leading_zeros as i32;
217                let mantissa = mantissa
218                    .checked_shl(leading_zeros as u32 + 1)
219                    .unwrap_or($guard_zero);
220                let (regime, exp) = Self::regime(exp_lhs + scaling_factor);
221                Self::_encode(sign, regime, exp.into(), mantissa)
222            }
223        }
224
225        impl<T> ::core::ops::Sub<T> for $name
226        where T: Into<$name>
227        {
228            type Output = $name;
229            fn sub(self, other: T) -> $name { self + (-(other.into())) }
230        }
231
232        impl<T> ::core::ops::Mul<T> for $name
233        where T: Into<$name>
234        {
235            type Output = $name;
236            fn mul(self, other: T) -> $name {
237                let other = other.into();
238                let sign = self.is_negative() != other.is_negative();
239                let (lhs, rhs) = match (self.decode(), other.decode()) {
240                    (Err(PositDecodeError::NaR), _) | (_, Err(PositDecodeError::NaR)) => {
241                        return Self::NAR;
242                    }
243                    (Err(PositDecodeError::Zero), _) | (_, Err(PositDecodeError::Zero)) => {
244                        return Self::ZERO;
245                    }
246                    (Ok(l), Ok(r)) => (l, r),
247                };
248                let exp_lhs = Self::exp(lhs.1, lhs.2);
249                let exp_rhs = Self::exp(rhs.1, rhs.2);
250                let mantissa_lhs = $guard::from((lhs.3 >> 2) | (Self::NAR.0 >> 1));
251                let mantissa_rhs = $guard::from((rhs.3 >> 2) | (Self::NAR.0 >> 1));
252                let mut mantissa = mantissa_lhs * mantissa_rhs;
253                let shift = mantissa.leading_zeros();
254                let scaling_factor = 3 - shift as i32;
255                mantissa <<= shift as usize;
256                mantissa <<= 1;
257                let (regime, exp) = Self::regime(exp_lhs + exp_rhs + scaling_factor);
258                Self::_encode(sign, regime, exp.into(), mantissa)
259            }
260        }
261
262        impl<T> ::core::ops::Div<T> for $name
263        where T: Into<$name>
264        {
265            type Output = $name;
266            fn div(self, other: T) -> $name {
267                let other = other.into();
268                let sign = self.is_negative() != other.is_negative();
269                let (lhs, rhs) = match (self.decode(), other.decode()) {
270                    (Err(PositDecodeError::NaR), _) | (_, Err(PositDecodeError::NaR)) => {
271                        return Self::NAR;
272                    }
273                    (_, Err(PositDecodeError::Zero)) => return Self::NAR,
274                    (Err(PositDecodeError::Zero), _) => return Self::ZERO,
275                    (Ok(l), Ok(r)) => (l, r),
276                };
277                let exp_lhs = Self::exp(lhs.1, lhs.2);
278                let exp_rhs = Self::exp(rhs.1, rhs.2);
279                let mut mantissa_lhs = $guard::from((lhs.3 >> 1) | Self::NAR.0);
280                let mut mantissa_rhs = $guard::from((rhs.3 >> 1) | Self::NAR.0);
281                let cut_lhs = mantissa_lhs.leading_zeros();
282                let cut_rhs = mantissa_rhs.trailing_zeros();
283                mantissa_lhs <<= cut_lhs as usize;
284                mantissa_rhs >>= cut_rhs as usize;
285                let mantissa = mantissa_lhs / mantissa_rhs;
286                let rem = mantissa_lhs % mantissa_rhs;
287                let cut_rem = rem.leading_zeros();
288                let rem_mantissa = match rem != $guard_zero {
289                    true => (rem << cut_rem as usize) / mantissa_rhs,
290                    false => rem,
291                };
292                let shift = mantissa.leading_zeros();
293                let scaling_factor =
294                    $bits as i32 * 2 - 1 - shift as i32 - (cut_lhs + cut_rhs) as i32;
295                let mantissa = mantissa
296                    .checked_shl(shift as u32 + 1)
297                    .unwrap_or($guard_zero);
298                let rem_mantissa = rem_mantissa
299                    .checked_shr(cut_rem - shift - 1)
300                    .unwrap_or($guard_zero);
301                let (regime, exp) = Self::regime(exp_lhs - exp_rhs + scaling_factor);
302                Self::_encode(sign, regime, exp.into(), mantissa | rem_mantissa)
303            }
304        }
305
306        impl ::core::ops::AddAssign for $name {
307            #[inline]
308            fn add_assign(&mut self, other: Self) { *self = *self + other }
309        }
310
311        impl ::core::ops::SubAssign for $name {
312            #[inline]
313            fn sub_assign(&mut self, other: Self) { *self = *self - other }
314        }
315
316        impl ::core::ops::MulAssign for $name {
317            #[inline]
318            fn mul_assign(&mut self, other: Self) { *self = *self * other }
319        }
320
321        impl ::core::ops::DivAssign for $name {
322            #[inline]
323            fn div_assign(&mut self, other: Self) { *self = *self / other }
324        }
325
326        impl ::core::fmt::Debug for $name {
327            fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
328                let &$name(ref data) = self;
329                write!(f, "{:?}", data)?;
330                Ok(())
331            }
332        }
333
334        impl From<$name> for f32 {
335            fn from(init: $name) -> f32 {
336                let (sign, regime, exp, mantissa): (bool, i16, $internal, $internal) =
337                    match init.decode() {
338                        Err(PositDecodeError::Zero) => return 0.,
339                        Err(PositDecodeError::NaR) => return f32::NAN,
340                        Ok(v) => v,
341                    };
342                let sign = if sign { 0x80000000u32 } else { 0u32 };
343                let exp = $name::exp(regime, exp);
344                let (exp, mantissa) = match (exp > 127, exp < -149, exp < -126) {
345                    (true, _, _) => return f32::MAX,
346                    (_, true, _) => return f32::MIN,
347                    (_, _, true) => (0u32, ((mantissa >> 1) | $nar) >> (-127 - exp) as usize),
348                    _ => (((exp + 127) as u32) << 23, mantissa),
349                };
350                let mut m = [0u8; 4];
351                let _ = mantissa
352                    .to_be_bytes()
353                    .iter()
354                    .enumerate()
355                    .filter(|&(i, _)| i < 4)
356                    .map(|(i, e)| m[i] = *e)
357                    .collect::<()>();
358                f32::from_bits(sign | exp | u32::from_be_bytes(m) >> 9)
359            }
360        }
361
362        impl From<f32> for $name {
363            fn from(init: f32) -> $name {
364                if init == 0. {
365                    return Self::ZERO;
366                }
367                if init.is_infinite() || init.is_nan() {
368                    return Self::NAR;
369                }
370                let bits = (if init.is_sign_negative() { -init } else { init }).to_bits();
371                let mut mantissa = [0u8; $bits * 2 / 8];
372                let _ = (bits << 9)
373                    .to_be_bytes()
374                    .iter()
375                    .enumerate()
376                    .filter(|&(i, _)| i < $bits * 2 / 8)
377                    .map(|(i, e)| mantissa[i] = *e)
378                    .collect::<()>();
379                let (mantissa, init_exp) = match init.is_normal() {
380                    true => ($guard::from_be_bytes(mantissa), (bits >> 23) as i16 - 127),
381                    false => {
382                        let m = $guard::from_be_bytes(mantissa);
383                        let shift = m.leading_zeros() + 1;
384                        (m << shift as usize, -126 - shift as i16)
385                    }
386                };
387                let (regime, exp) = Self::regime(init_exp);
388                Self::_encode(init.is_sign_negative(), regime, exp.into(), mantissa)
389            }
390        }
391
392        impl From<$name> for f64 {
393            fn from(init: $name) -> f64 {
394                let (sign, regime, exp, mantissa): (bool, i16, $internal, $internal) =
395                    match init.decode() {
396                        Err(PositDecodeError::Zero) => return 0.,
397                        Err(PositDecodeError::NaR) => return f64::NAN,
398                        Ok(v) => v,
399                    };
400                let sign = if sign { 0x80000000_00000000u64 } else { 0u64 };
401                let exp = $name::exp(regime, exp);
402                let (exp, mantissa) = match (exp > 1023, exp < -1074, exp < -1022) {
403                    (true, _, _) => return f64::MAX,
404                    (_, true, _) => return f64::MIN,
405                    (_, _, true) => (0u64, ((mantissa >> 1) | $nar) >> (-1023 - exp) as usize),
406                    _ => (((exp + 1023) as u64) << 52, mantissa),
407                };
408                let mut m = [0u8; 8];
409                let _ = mantissa
410                    .to_be_bytes()
411                    .iter()
412                    .enumerate()
413                    .filter(|&(i, _)| i < 8)
414                    .map(|(i, e)| m[i] = *e)
415                    .collect::<()>();
416                f64::from_bits(sign | exp | u64::from_be_bytes(m) >> 12)
417            }
418        }
419
420        impl From<f64> for $name {
421            fn from(init: f64) -> $name {
422                if init == 0. {
423                    return Self::ZERO;
424                }
425                if init.is_infinite() || init.is_nan() {
426                    return Self::NAR;
427                }
428                let bits = (if init.is_sign_negative() { -init } else { init }).to_bits();
429                let mut mantissa = [0u8; $bits * 2 / 8];
430                let _ = (bits << 12)
431                    .to_be_bytes()
432                    .iter()
433                    .enumerate()
434                    .filter(|&(i, _)| i < $bits * 2 / 8)
435                    .map(|(i, e)| mantissa[i] = *e)
436                    .collect::<()>();
437                let (mantissa, init_exp) = match init.is_normal() {
438                    true => ($guard::from_be_bytes(mantissa), (bits >> 52) as i16 - 1023),
439                    false => {
440                        let m = $guard::from_be_bytes(mantissa);
441                        let shift = m.leading_zeros() + 1;
442                        (m << shift as usize, -1022 - shift as i16)
443                    }
444                };
445                let (regime, exp) = Self::regime(init_exp);
446                Self::_encode(init.is_sign_negative(), regime, exp.into(), mantissa)
447            }
448        }
449    };
450}
451
452construct_posit!(Posit8, 8, 0, u8, 0, u8::MAX, 0x80, u16, 0, u16::MAX, to_u8, into_u8);
453construct_posit!(Posit16, 16, 1, u16, 0, u16::MAX, 0x8000, u32, 0, u32::MAX, to_u16, into_u16);
454construct_posit!(Posit32, 32, 2, u32, 0, u32::MAX, 0x8000_0000, u64, 0, u64::MAX, to_u32, into_u32);
455construct_posit!(
456    Posit64,
457    64,
458    3,
459    u64,
460    0,
461    u64::MAX,
462    0x8000_0000_0000_0000,
463    u128,
464    0,
465    u128::MAX,
466    to_u64,
467    into_u64
468);
469construct_posit!(
470    Posit128,
471    128,
472    4,
473    u128,
474    0,
475    u128::MAX,
476    0x8000_0000_0000_0000_0000_0000_0000_0000,
477    u256,
478    u256::ZERO,
479    u256::MAX,
480    to_u128,
481    into_u128
482);
483construct_posit!(
484    Posit256,
485    256,
486    5,
487    u256,
488    u256::ZERO,
489    u256::MAX,
490    u256::from_inner([0, 0, 0, 0x8000_0000_0000_0000]),
491    u512,
492    u512::ZERO,
493    u512::MAX,
494    to_u256,
495    into_u256
496);
497construct_posit!(
498    Posit512,
499    512,
500    6,
501    u512,
502    u512::ZERO,
503    u512::MAX,
504    u512::from_inner([0, 0, 0, 0, 0, 0, 0, 0x8000_0000_0000_0000]),
505    u1024,
506    u1024::ZERO,
507    u1024::MAX,
508    to_u512,
509    into_u512
510);
511
512#[cfg(test)]
513mod tests {
514    #![allow(unused)]
515
516    use super::*;
517
518    construct_posit!(Posit8Es1, 8, 1, u8, 0, 0xff, 0x80, u16, 0, 0xffff, to_u8, into_u8);
519
520    #[test]
521    fn posit_test() {
522        assert_eq!(Posit16::from(1.).into_u16(), 0b0100_0000_0000_0000);
523        assert_eq!(Posit16::from(1.125).into_u16(), 0b0100_0010_0000_0000);
524        assert_eq!(Posit16::from(3.25).into_u16(), 0b0101_1010_0000_0000);
525        assert_eq!(Posit16::from(4.).into_u16(), 0b0110_0000_0000_0000);
526        assert_eq!(Posit16::from(8.).into_u16(), 0b0110_1000_0000_0000);
527        assert_eq!(Posit16::from(1024.).into_u16(), 0b0111_1110_0000_0000);
528        assert_eq!(Posit16::from(-10.).into_u16(), 0b1001_0110_0000_0000);
529        assert_eq!(Posit16::from(-7. / 16.).into_u16(), 0b1101_0100_0000_0000);
530        assert_eq!(Posit16::from(-256.).into_u16(), 0b1000_0100_0000_0000);
531        assert_eq!(Posit16::from(0.).into_u16(), 0b0000_0000_0000_0000);
532        assert_eq!(Posit16::from(-0.).into_u16(), 0b0000_0000_0000_0000);
533    }
534
535    #[test]
536    fn posit_from_subnormal_test() {
537        let sub = f32::from_bits(0b0000_0000_0000_1000 << 16); //2 ^ (-130)
538        assert!(!sub.is_normal());
539        // With es = 3, regime is -17 and exp is 6. -17 * 8 + 6 = 130
540        assert_eq!(Posit64::from(sub).into_u64(), 0b0000_0000_0000_0000_0011_1000 << 40);
541        assert_eq!(f32::from(Posit64::from(sub)), sub);
542    }
543
544    #[test]
545    fn posit8es1_test() {
546        assert_eq!(Posit8Es1::from(1.).into_u8(), 0b0100_0000);
547        assert_eq!(Posit8Es1::from(1.125).into_u8(), 0b0100_0010);
548        assert_eq!(Posit8Es1::from(3.25).into_u8(), 0b0101_1010);
549        assert_eq!(Posit8Es1::from(4.).into_u8(), 0b0110_0000);
550        assert_eq!(Posit8Es1::from(8.).into_u8(), 0b0110_1000);
551        assert_eq!(Posit8Es1::from(1024.).into_u8(), 0b0111_1110);
552        assert_eq!(Posit8Es1::from(-10.).into_u8(), 0b1001_0110);
553        assert_eq!(Posit8Es1::from(-7. / 16.).into_u8(), 0b1101_0100);
554        assert_eq!(Posit8Es1::from(-256.).into_u8(), 0b1000_0100);
555    }
556
557    #[test]
558    fn posit32_test() {
559        assert_eq!(Posit32::from(1.).into_u32(), 0b0100_0000 << 24);
560    }
561
562    #[test]
563    fn posit256_test() {
564        assert_eq!(Posit256::from(1.).into_u256(), u256::from(0b0100_0000u64) << 248);
565        assert_eq!(Posit256::from(1.125).into_u256(), u256::from(0b0100_0000_0010_0000u64) << 240);
566    }
567
568    #[test]
569    fn posit8_es1_round_test() {
570        assert_eq!(Posit8Es1::from(0.9999), Posit8Es1::from(1.));
571        assert_eq!(Posit8Es1::from(73. / 64.), Posit8Es1::from(18. / 16.));
572        assert_eq!(Posit8Es1::from(74. / 64.), Posit8Es1::from(18. / 16.));
573        assert_eq!(Posit8Es1::from(75. / 64.), Posit8Es1::from(19. / 16.));
574        assert_eq!(
575            Posit8Es1::encode(true, 1, 1, 0b0111_1111u8),
576            Posit8Es1::encode(true, 1, 1, 0b1000_0000u8),
577        );
578        assert_eq!(
579            Posit8Es1::encode(true, 1, 0, 0b1111_1111u8),
580            Posit8Es1::encode(true, 1, 1, 0b0000_0000u8),
581        );
582        assert_eq!(
583            Posit8Es1::encode(true, 1, 1, 0b1111_1111u8),
584            Posit8Es1::encode(true, 2, 0, 0b0000_0000u8),
585        );
586    }
587
588    #[test]
589    fn posit256_nar_test() {
590        assert_eq!(Posit256::from(f32::INFINITY), Posit256::NAR);
591        assert_eq!(Posit256::from(f32::NEG_INFINITY), Posit256::NAR);
592        assert_eq!(Posit256::from(f32::NAN), Posit256::NAR);
593    }
594
595    #[test]
596    fn posit_neg_test() {
597        assert_eq!((-Posit256::from(1.)).into_u256(), Posit256::from(-1.).into_u256(),);
598        assert_eq!((-Posit256::from(0.)).into_u256(), Posit256::from(0.).into_u256(),);
599    }
600
601    #[test]
602    fn posit_is_nar_test() {
603        assert!(Posit256::from(f32::INFINITY).is_nar());
604        assert!(Posit256::from(f32::NEG_INFINITY).is_nar());
605        assert!(Posit256::from(f32::NAN).is_nar());
606        assert!(!(Posit256::ZERO.is_nar()));
607        assert!(!(Posit256::from(1.).is_nar()));
608    }
609
610    #[test]
611    fn posit_is_negative_test() {
612        assert!(!(Posit256::from(f32::INFINITY).is_negative()));
613        assert!(!(Posit256::from(f32::NEG_INFINITY).is_negative()));
614        assert!(!(Posit256::from(f32::NAN).is_negative()));
615        assert!(!(Posit256::from(0.)).is_negative());
616        assert!(!(Posit256::from(3.)).is_negative());
617        assert!(Posit256::from(-2.).is_negative());
618    }
619
620    #[test]
621    fn posit_is_positive_test() {
622        assert!(!(Posit256::from(f32::INFINITY).is_positive()));
623        assert!(!(Posit256::from(f32::NEG_INFINITY).is_positive()));
624        assert!(!(Posit256::from(f32::NAN).is_positive()));
625        assert!(!(Posit256::from(0.)).is_positive());
626        assert!(Posit256::from(3.).is_positive());
627        assert!(!(Posit256::from(-2.).is_positive()));
628    }
629
630    #[test]
631    fn posit_is_zero_test() {
632        assert!(!(Posit256::from(f32::INFINITY).is_zero()));
633        assert!(!(Posit256::from(f32::NEG_INFINITY).is_zero()));
634        assert!(!(Posit256::from(f32::NAN).is_zero()));
635        assert!(Posit256::from(0.).is_zero());
636        assert!(!(Posit256::from(3.).is_zero()));
637        assert!(!(Posit256::from(-2.).is_zero()));
638    }
639
640    #[test]
641    fn posit_decode_test() {
642        assert_eq!(Posit8Es1::encode(false, 1, 1, 0x80u8), Posit8Es1::from(12.));
643        assert_eq!(Ok((false, 1, 1, 0x80)), Posit8Es1::from(12.).decode());
644        assert_eq!(Posit16::encode(true, 1, 1, 0x8000u16), Posit16::from(-12.));
645        assert_eq!(Ok((true, 1, 1, 0x8000)), Posit16::from(-12.).decode());
646        assert_eq!(Ok((false, 0, 0, 0b00001000)), Posit8::from(1.03125).decode());
647    }
648
649    #[test]
650    #[allow(clippy::nonminimal_bool)]
651    fn posit_cmp_test() {
652        assert!(Posit16::from(4.) < Posit16::from(5.));
653        assert!(Posit16::from(0.) <= (Posit16::from(0.)));
654        assert!(!(Posit16::from(0.) > (Posit16::from(0.))));
655        assert!(Posit16::from(-1.) < Posit16::from(-0.9));
656        assert!(Posit16::from(-2.) < Posit16::from(3.));
657        assert!(Posit16::NAR < Posit16::from(0.));
658        assert!(Posit16::NAR < Posit16::from(3.));
659        assert!(Posit16::NAR < Posit16::from(-0.2));
660        assert!(Posit16::NAR <= (Posit16::NAR));
661        assert!(!(Posit16::NAR > (Posit16::NAR)));
662    }
663
664    #[test]
665    fn posit_add_test() {
666        assert_eq!(Posit16::from(-1.) + Posit16::from(-2.), Posit16::from(-3.));
667        assert_eq!(Posit16::from(-1.) + Posit16::from(2.25), Posit16::from(1.25));
668        assert_eq!(Posit16::from(1.) + Posit16::from(2.), Posit16::from(3.));
669        assert_eq!(Posit16::from(16.) + Posit16::from(-64.), Posit16::from(-48.));
670        assert_eq!(Posit16::from(2.125) + Posit16::from(3.5), Posit16::from(5.625));
671        assert_eq!(Posit16::from(1.3) + Posit16::from(3.0), Posit16::from(4.3));
672        assert_eq!(Posit16::from(1. / 3.) + Posit16::from(1. / 3.), Posit16::from(2. / 3.));
673        assert_eq!(Posit16::from(4.) + Posit16::from(0.), Posit16::from(4.));
674        assert_eq!(Posit16::from(0.) + Posit16::from(3.), Posit16::from(3.));
675        assert_eq!(Posit16::from(0.) + Posit16::from(0.), Posit16::from(0.));
676        assert_eq!(Posit16::NAR + Posit16::from(3.), Posit16::NAR);
677        assert_eq!(Posit16::from(0.) + Posit16::NAR, Posit16::NAR);
678        assert_eq!(Posit8::from(10.) + Posit8::from(1.0935), Posit8::from(12.));
679        assert_eq!(Posit8::from(10.) + Posit8::from(-10.), Posit8::from(0.));
680        assert_eq!(
681            Posit16::from(
682                f64::from(Posit16::from_bits(32769)) + f64::from(Posit16::from_bits(1457))
683            ),
684            Posit16::from_bits(32769)
685        );
686    }
687
688    #[test]
689    fn posit_add_assign_test() {
690        let mut x = Posit8::from(1.0);
691        x += Posit8::from(2.0);
692        assert_eq!(x, Posit8::from(3.0))
693    }
694
695    #[test]
696    fn posit_sub_assign_test() {
697        let mut x = Posit8::from(1.0);
698        x -= Posit8::from(2.0);
699        assert_eq!(x, Posit8::from(-1.0))
700    }
701
702    #[test]
703    fn posit_mul_assign_test() {
704        let mut x = Posit8::from(2.0);
705        x *= Posit8::from(3.0);
706        assert_eq!(x, Posit8::from(6.0))
707    }
708
709    #[test]
710    fn posit_div_assign_test() {
711        let mut x = Posit8::from(1.0);
712        x /= Posit8::from(2.0);
713        assert_eq!(x, Posit8::from(0.5))
714    }
715
716    #[test]
717    fn posit_sub_test() {
718        assert_eq!(Posit16::from(-1.) - Posit16::from(-2.), Posit16::from(1.));
719        assert_eq!(Posit16::from(-1.) - Posit16::from(2.25), Posit16::from(-3.25));
720        assert_eq!(Posit16::from(6.) - Posit16::from(-4.25), Posit16::from(10.25));
721        assert_eq!(Posit16::from(1.) - Posit16::from(2.), Posit16::from(-1.));
722        assert_eq!(Posit16::from(2.125) - Posit16::from(3.5), Posit16::from(-1.375));
723    }
724
725    #[test]
726    fn posit_mul_test() {
727        assert_eq!(Posit16::from(2.) * Posit16::from(3.), Posit16::from(6.));
728        assert_eq!(Posit16::from(1.25) * Posit16::from(3.5), Posit16::from(4.375));
729        assert_eq!(Posit16::from(-0.5) * Posit16::from(8.), Posit16::from(-4.));
730        assert_eq!(Posit16::from(-16.) * Posit16::from(-16.), Posit16::from(256.));
731        assert_eq!(Posit16::from(7.) * Posit16::from(0.), Posit16::from(0.));
732        assert_eq!(Posit16::NAR * Posit16::from(3.), Posit16::NAR);
733        assert_eq!(Posit16::from(0.) * Posit16::NAR, Posit16::NAR);
734    }
735
736    #[test]
737    fn posit_div_test() {
738        assert_eq!(Posit16::from(1.) / Posit16::from(2.), Posit16::from(0.5));
739        assert_eq!(Posit16::from(1.) / Posit16::from(8.), Posit16::from(0.125));
740        assert_eq!(Posit32::from(1.) / Posit32::from(8.), Posit32::from(0.125));
741        assert_eq!(Posit32::from(1.) / Posit32::from(64.), Posit32::from(1. / 64.));
742        assert_eq!(Posit8::from(1.75) / Posit8::from(1.), Posit8::from(1.75));
743        assert_eq!(Posit8::from(-3.) / Posit8::from(1.15625), Posit8::from(-2.625));
744    }
745
746    fn rand_posit8(fun: fn(Posit8, Posit8, f32, f32) -> (Posit8, f32)) {
747        use rand::Rng;
748        let mut rng = rand::thread_rng();
749        for _ in 0..100000 {
750            let x: u8 = rng.gen();
751            let y: u8 = rng.gen();
752            let (p, f) = fun(
753                Posit8::from_bits(x),
754                Posit8::from_bits(y),
755                f32::from(Posit8::from_bits(x)),
756                f32::from(Posit8::from_bits(y)),
757            );
758            assert_eq!(p, Posit8::from(f));
759        }
760    }
761
762    fn rand_posit16(fun: fn(Posit16, Posit16, f64, f64) -> (Posit16, f64)) {
763        use rand::Rng;
764        let mut rng = rand::thread_rng();
765        for _ in 0..100000 {
766            let x: u16 = rng.gen();
767            let y: u16 = rng.gen();
768            let (p, f) = fun(
769                Posit16::from_bits(x),
770                Posit16::from_bits(y),
771                f64::from(Posit16::from_bits(x)),
772                f64::from(Posit16::from_bits(y)),
773            );
774            assert_eq!(p, Posit16::from(f));
775        }
776    }
777
778    #[test]
779    fn posit8_add() { rand_posit8(|p_a, p_b, f_a, f_b| (p_a + p_b, f_a + f_b)); }
780
781    #[test]
782    fn posit8_sub() { rand_posit8(|p_a, p_b, f_a, f_b| (p_a - p_b, f_a - f_b)); }
783
784    #[test]
785    fn posit8_mul() { rand_posit8(|p_a, p_b, f_a, f_b| (p_a * p_b, f_a * f_b)); }
786
787    #[test]
788    fn posit8_div() { rand_posit8(|p_a, p_b, f_a, f_b| (p_a / p_b, f_a / f_b)); }
789
790    #[test]
791    fn posit16_add() { rand_posit16(|p_a, p_b, f_a, f_b| (p_a + p_b, f_a + f_b)); }
792
793    #[test]
794    fn posit16_sub() { rand_posit16(|p_a, p_b, f_a, f_b| (p_a - p_b, f_a - f_b)); }
795
796    #[test]
797    fn posit16_mul() { rand_posit16(|p_a, p_b, f_a, f_b| (p_a * p_b, f_a * f_b)); }
798
799    #[test]
800    fn posit16_div() { rand_posit16(|p_a, p_b, f_a, f_b| (p_a / p_b, f_a / f_b)); }
801}