1use 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); assert!(!sub.is_normal());
539 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}