Skip to main content

fast_posit/posit/
consts.rs

1use super::*;
2use crate::underlying::const_as;
3
4impl<
5  const N: u32,
6  const ES: u32,
7  Int: crate::Int,
8  const RS: u32,
9> Posit<N, ES, Int, RS> {
10  /// Zero (`0`), the additive identity element.
11  pub const ZERO: Self = Self(Int::ZERO);
12
13  /// NAR is the `0b1000...` bit pattern, appropriately sign-extended. This is that number
14  /// represented as an i128 (max width of any Int).
15  const NAR_I128: i128 = i128::MIN >> (128 - Int::BITS + Self::JUNK_BITS);
16
17  /// Not-a-real (`NaR`).
18  //
19  // Represented by the bit pattern `0b1000...0`.
20  pub const NAR: Self = Self(const_as(Self::NAR_I128));
21
22  /// One (`1`), the additive identity element.
23  //
24  // Represented by the bit pattern `0b0100...0`.
25  pub const ONE: Self = Self(const_as(-(Self::NAR_I128 >> 1)));
26
27  /// Negative one (`-1`).
28  //
29  // Represented by the bit pattern `0b1100...0`.
30  pub const MINUS_ONE: Self = Self(const_as(Self::NAR_I128 >> 1));
31
32  /// Greatest representable value, equal to `-MIN`.
33  //
34  // Represented by the bit pattern `0b0111...1`.
35  pub const MAX: Self = Self(const_as(!Self::NAR_I128));
36
37  /// Smallest representable value, equal to `-MAX`.
38  ///
39  /// Not to be confused with the smallest *absolute value*, i.e. [`Self::MIN_POSITIVE`].
40  //
41  // Represented by the bit pattern `0b100...01`.
42  pub const MIN: Self = Self(const_as(Self::NAR_I128 + 1));
43
44  /// Smallest *positive* value, equal to `-MAX_NEGATIVE`.
45  //
46  // Represented by the bit pattern `0b000...01`.
47  pub const MIN_POSITIVE: Self = Self(Int::ONE);
48
49  /// Largest *negative* value, equal to `-MIN_POSITIVE`.
50  //
51  // Represented by the bit pattern `0b1111...1`.
52  pub const MAX_NEGATIVE: Self = Self(const_as(-1));
53
54  /// The largest *consecutive* integer value, that is: integers in the range `0 ..= Self::INT_MAX`
55  /// are exactly representable as a posit of this type.
56  ///
57  /// Standard: "[**pIntMax**](https://posithub.org/docs/posit_standard-2.pdf#subsection.3.2)".
58  ///
59  /// # Example
60  ///
61  /// ```
62  /// # use fast_posit::*;
63  /// assert_eq!(p8::INT_MAX, 1 << 4);
64  /// assert_eq!(p16::INT_MAX, 1 << 10);
65  /// assert_eq!(p32::INT_MAX, 1 << 23);
66  /// assert_eq!(p64::INT_MAX, 1 << 48);
67  /// ```
68  pub const INT_MAX: Int = Self::int_max();
69
70  const fn int_max() -> Int {
71    // If a (positive) power of two is representable as a posit, it looks like this:
72    //
73    //   0b0_11…10_ee_000000…
74    //
75    // A 0 sign bit, a positive `regime` represented by a sequence of `regime + 1` 1s terminated by
76    // a 0, then `ES` exponent bits, then 0s all the way through the end for the fraction bits.
77    //
78    // To figure out what's the maximum integer such that all numbers from 0 to that integer are
79    // exactly representable as a posit, let's work by induction by thinking like this: the number
80    // `1` is always representable as a posit. Then, if a positive power of two `1 << power` is
81    // representable as a posit, the next number is representable if
82    //
83    //   0b0_11…10_ee_000…001000…
84    //
85    // is representable as a posit, where there are `power - 1` 0s in the fraction before the 1.
86    //
87    // If this is the case, then all the numbers up to the next power of two are also representable
88    //
89    //   0b0_11…10_ee_000…010000…
90    //   0b0_11…10_ee_000…011000…
91    //   0b0_11…10_ee_000…100000…
92    //   …
93    //
94    // But we also know that the number of fraction bits is `N - 1 - (regime + 1) - 1 - ES`.
95    // Therefore, if this number is smaller than `power`, then we cannot represent the integer
96    // after `1 << power` as a posit without rounding, meaning `1 << power` is the largest
97    // consecutive integer representable as this posit.
98    //
99    // So we just iterate through powers of two until we find the biggest representable `power`;
100    // the answer is `1 << power`.
101    let mut power = 0;
102    while power < Int::BITS {
103      let regime = power >> ES;
104      // If not even enough bits to represent the regime and exponent fields, this is `INT_MAX`.
105      if Self::BITS < regime + ES + 3 {
106        return const_as::<i128, Int>(1 << power)
107      }
108      // Otherwise we have `fraction_bits` left over, if we cannot represent the next integer, this
109      // is `INT_MAX`.
110      let fraction_bits = Self::BITS - regime - ES - 3;
111      if fraction_bits < power {
112        return const_as::<i128, Int>(1 << power)
113      }
114      power += 1
115    }
116    unreachable!()
117  }
118
119  /// The maximum (absolute value of the) regime.
120  ///
121  /// It is equal to 1 less than the maximum length of the regime, therefore equal to
122  /// `Self::BITS - 2` or `Self::RS`, whichever is larger.
123  pub(crate) const MAX_REGIME: u32 = {
124    if RS >= N - 2 {N - 2} else {RS}
125  };
126
127  /// The maximum exponent; [`Self::MAX`] = 2 <sup>[`Self::MAX_EXP`]</sup>. Equal to
128  /// `-MIN_EXP`.
129  pub(crate) const MAX_EXP: Int = {
130    let max_regime = Self::MAX_REGIME as i128;
131    let max_exp = max_regime << ES;
132    const_as(max_exp)
133  };
134}
135
136#[cfg(test)]
137#[allow(overflowing_literals)]
138mod tests {
139  use super::*;
140
141  use malachite::rational::Rational;
142
143  #[test]
144  fn zero() {
145    assert_eq!(
146      Posit::<16, 2, i16>::ZERO.to_bits(),
147      0,
148    );
149    assert_eq!(
150      Posit::<10, 1, i16>::ZERO.to_bits(),
151      0,
152    );
153    assert_eq!(
154      Rational::try_from(Posit::<10, 1, i16>::ZERO),
155      Ok(Rational::from(0)),
156    );
157    assert_eq!(
158      Posit::<16, 5, i16, 6>::ZERO.to_bits(),
159      0,
160    );
161  }
162
163  #[test]
164  fn nar() {
165    assert_eq!(
166      Posit::<16, 2, i16>::NAR.to_bits(),
167      0b1000_0000_0000_0000,
168    );
169    assert_eq!(
170      Posit::<10, 1, i16>::NAR.to_bits(),
171      0b111111_10_0000_0000,
172    );
173    assert_eq!(
174      Rational::try_from(Posit::<10, 1, i16>::NAR),
175      Err(super::rational::IsNaR),
176    );
177    assert_eq!(
178      Posit::<16, 5, i16, 6>::NAR.to_bits(),
179      0b1000_0000_0000_0000,
180    );
181  }
182
183  #[test]
184  fn min_positive() {
185    assert_eq!(
186      Posit::<16, 2, i16>::MIN_POSITIVE.to_bits(),
187      0b0000_0000_0000_0001,
188    );
189    assert_eq!(
190      Posit::<10, 1, i16>::MIN_POSITIVE.to_bits(),
191      0b000000_00_0000_0001,
192    );
193    assert_eq!(
194      Rational::try_from(Posit::<10, 1, i16>::MIN_POSITIVE),
195      Ok(Rational::from_signeds(1, (1i64 << 2).pow(10 - 2))),
196    );
197    assert_eq!(
198      Posit::<16, 5, i16, 6>::MIN_POSITIVE.to_bits(),
199      0b000000_00_0000_0001,
200    );
201  }
202
203  #[test]
204  fn max() {
205    assert_eq!(
206      Posit::<16, 2, i16>::MAX.to_bits(),
207      0b0111_1111_1111_1111,
208    );
209    assert_eq!(
210      Posit::<10, 1, i16>::MAX.to_bits(),
211      0b000000_01_1111_1111,
212    );
213    assert_eq!(
214      Rational::try_from(Posit::<10, 1, i16>::MAX),
215      Ok(Rational::from((1i64 << 2).pow(10 - 2))),
216    );
217    assert_eq!(
218      Posit::<16, 5, i16, 6>::MAX.to_bits(),
219      0b0111_1111_1111_1111,
220    );
221  }
222
223  #[test]
224  fn max_negative() {
225    assert_eq!(
226      Posit::<16, 2, i16>::MAX_NEGATIVE.to_bits(),
227      0b1111_1111_1111_1111,
228    );
229    assert_eq!(
230      Posit::<10, 1, i16>::MAX_NEGATIVE.to_bits(),
231      0b111111_11_1111_1111,
232    );
233    assert_eq!(
234      Rational::try_from(Posit::<10, 1, i16>::MAX_NEGATIVE),
235      Ok(-Rational::from_signeds(1, (1i64 << 2).pow(10 - 2))),
236    );
237    assert_eq!(
238      Posit::<16, 5, i16, 6>::MAX_NEGATIVE.to_bits(),
239      0b1111_1111_1111_1111,
240    );
241  }
242
243  #[test]
244  fn min() {
245    assert_eq!(
246      Posit::<16, 2, i16>::MIN.to_bits(),
247      0b1000_0000_0000_0001,
248    );
249    assert_eq!(
250      Posit::<10, 1, i16>::MIN.to_bits(),
251      0b111111_10_0000_0001,
252    );
253    assert_eq!(
254      Rational::try_from(Posit::<10, 1, i16>::MIN),
255      Ok(-Rational::from((1i64 << 2).pow(10 - 2))),
256    );
257    assert_eq!(
258      Posit::<16, 5, i16, 6>::MIN.to_bits(),
259      0b1000_0000_0000_0001,
260    );
261  }
262
263  #[test]
264  fn one() {
265    assert_eq!(
266      Posit::<16, 2, i16>::ONE.to_bits(),
267      0b0100_0000_0000_0000,
268    );
269    assert_eq!(
270      Posit::<10, 1, i16>::ONE.to_bits(),
271      0b000000_01_0000_0000,
272    );
273    assert_eq!(
274      Rational::try_from(Posit::<10, 1, i16>::ONE),
275      Ok(Rational::from(1)),
276    );
277    assert_eq!(
278      Posit::<16, 5, i16, 6>::ONE.to_bits(),
279      0b0100_0000_0000_0000,
280    );
281  }
282
283  #[test]
284  fn minus_one() {
285    assert_eq!(
286      Posit::<16, 2, i16>::MINUS_ONE.to_bits(),
287      0b1100_0000_0000_0000,
288    );
289    assert_eq!(
290      Posit::<10, 1, i16>::MINUS_ONE.to_bits(),
291      0b111111_11_0000_0000,
292    );
293    assert_eq!(
294      Rational::try_from(Posit::<10, 1, i16>::MINUS_ONE),
295      Ok(-Rational::from(1)),
296    );
297    assert_eq!(
298      Posit::<16, 5, i16, 6>::MINUS_ONE.to_bits(),
299      0b1100_0000_0000_0000,
300    );
301  }
302
303  #[test]
304  fn int_max() {
305    fn b_exhaustive<const N: u32, const ES: u32, Int: crate::Int, const RS: u32>() {
306      use crate::RoundInto;
307      // All numbers from 0 to INT_MAX round-trip losslessly to posit
308      let int_max: i32 = const_as(Posit::<N, ES, Int>::INT_MAX);
309      for int in 0 ..= int_max {
310        let posit: Posit::<N, ES, Int> = int.round_into();
311        let re_int: i32 = posit.round_into();
312        assert_eq!(int, re_int)
313      }
314      // The number immediately after doesn't
315      let int_invalid: i32 = int_max + 1;
316      let posit_invalid: Posit::<N, ES, Int> = int_invalid.round_into();
317      let re_int_invalid: i32 = posit_invalid.round_into();
318      assert_ne!(int_invalid, re_int_invalid)
319    }
320    fn exhaustive<const N: u32, const ES: u32, Int: crate::Int>() {
321      b_exhaustive::<N, ES, Int, N>()
322    }
323
324    exhaustive::<10, 0, i16>();
325    exhaustive::<10, 1, i16>();
326    exhaustive::<10, 2, i16>();
327    exhaustive::<10, 3, i16>();
328    exhaustive::<8, 0, i8>();
329    exhaustive::<8, 2, i8>();
330    exhaustive::<16, 2, i16>();
331    exhaustive::<32, 2, i32>();
332    exhaustive::<3, 0, i8>();
333    exhaustive::<4, 0, i8>();
334    exhaustive::<4, 1, i8>();
335    b_exhaustive::<8, 3, i8, 6>();
336    b_exhaustive::<16, 5, i16, 6>();
337    b_exhaustive::<20, 5, i32, 6>();
338  }
339
340  /// Aux function: the max value of an n-bit posit with 2-bit exponent (as per the standard).
341  /// max = -min = 1/min_positive = -1/max_negative.
342  fn std_max(n: u32) -> Rational {
343    use malachite::base::num::arithmetic::traits::PowerOf2;
344    let n = i64::from(n);
345    Rational::power_of_2(4*n - 8)
346  }
347
348  macro_rules! std_tests {
349    ($t:ident) => {
350      mod $t {
351        use super::*;
352        use malachite::base::num::arithmetic::traits::Reciprocal;
353
354        #[test]
355        fn zero() {
356          assert_eq!(crate::$t::ZERO.try_into(), Ok(Rational::from(0)));
357        }
358
359        #[test]
360        fn nar() {
361          assert_eq!(Rational::try_from(crate::$t::NAR), Err(super::rational::IsNaR));
362        }
363
364        #[test]
365        fn min_positive() {
366          assert_eq!(crate::$t::MIN_POSITIVE.try_into(), Ok(std_max(crate::$t::BITS).reciprocal()));
367        }
368
369        #[test]
370        fn max() {
371          assert_eq!(crate::$t::MAX.try_into(), Ok(std_max(crate::$t::BITS)));
372        }
373
374        #[test]
375        fn max_negative() {
376          assert_eq!(crate::$t::MAX_NEGATIVE.try_into(), Ok(-std_max(crate::$t::BITS).reciprocal()));
377        }
378
379        #[test]
380        fn min() {
381          assert_eq!(crate::$t::MIN.try_into(), Ok(-std_max(crate::$t::BITS)));
382        }
383
384        #[test]
385        fn one() {
386          assert_eq!(crate::$t::ONE.try_into(), Ok(Rational::from(1)));
387        }
388
389        #[test]
390        fn minus_one() {
391          assert_eq!(crate::$t::MINUS_ONE.try_into(), Ok(-Rational::from(1)));
392        }
393      }
394    };
395  }
396
397  std_tests!{p8}
398  std_tests!{p16}
399  std_tests!{p32}
400  std_tests!{p64}
401}