fast_posit/posit/convert/
float.rs

1use super::*;
2
3use crate::underlying::const_as;
4
5/// Extract the mantissa and exponent fields of an [`f64`], and represent them as a
6/// [`Decoded`], plus any sticky bits that have been lost.
7fn decode_finite_f64<
8  const N: u32,
9  const ES: u32,
10  Int: crate::Int,
11>(num: f64) -> (Decoded<N, ES, Int>, Int) {  // TODO type for `(Decoded, sticky)`
12  debug_assert!(num.is_finite());
13  const MANTISSA_DIGITS_EXPLICIT: u32 = f64::MANTISSA_DIGITS - 1;
14  const EXP_BIAS: i64 = f64::MIN_EXP as i64 - 1;
15  const HIDDEN_BIT: i64 = (i64::MIN as u64 >> 1) as i64;
16
17  // Extract sign, mantissa, and exponent.
18  use crate::underlying::Sealed;
19  let sign = num.is_sign_positive();
20  let bits = num.abs().to_bits() as i64;
21  let mantissa = bits.mask_lsb(MANTISSA_DIGITS_EXPLICIT);
22  let mut exponent = bits >> MANTISSA_DIGITS_EXPLICIT;
23
24  // An exponent field of 0 marks a subnormal number. Normals have implicit unit (`1.xxx`) and -1
25  // bias in the exponent; subnormals don't.
26  let is_normal = exponent != 0;
27  exponent -= i64::from(is_normal);
28
29  // Represent the mantissa as a `frac` in the target type `Int`.
30  //
31  // First, the float `mantissa` field is (1) unsigned, and (2) does not contain the hidden bit, so
32  // we need to correct that. Note that, if `frac` is 1.000… (i.e. `mantissa` = 0), it's negation
33  // is not -1.000…, but rather -2.000… with -1 in the `exp`!
34  let frac: i64 = {
35    const SHIFT_LEFT: u32 = 64 - MANTISSA_DIGITS_EXPLICIT - 2;
36    let unsigned_frac = (mantissa << SHIFT_LEFT) | HIDDEN_BIT;
37    if sign {
38      unsigned_frac
39    } else if mantissa != 0 {
40      -unsigned_frac
41    } else {
42      exponent -= 1;
43      i64::MIN
44    }
45  };
46  // Then, the bits have to be moved, from a width of `i64` to a width of `Int`, which may be
47  // either narrower or wider than an `i64`. Bits lost, if any, have to be accumulated onto
48  // `sticky`, to be returned.
49  let (mut frac, sticky): (Int, Int) = {
50    let shift_left = Int::BITS as i64 - 64;
51    if shift_left >= 0 {
52      // The mantissa has to be shifted left: there are no bits lost.
53      let shift_left = shift_left as u32;
54      let frac = const_as::<i64, Int>(frac) << shift_left;
55      (frac, Int::ZERO)
56    } else {
57      // The mantissa has to be shifted right: that amount of bits are lost.
58      let shift_right = -shift_left as u32;
59      let sticky = Int::from(frac.mask_lsb(shift_right) != 0);
60      let frac = const_as::<i64, Int>(frac.lshr(shift_right));
61      (frac, sticky)
62    }
63  };
64
65  // If it's a subnormal, then `frac` is "underflowing". We have to find the first 1 after the 0s,
66  // or the first 0 after the 1, and shift it to the correct place.
67  //
68  // Examples:
69  //
70  //   subnormal frac: 0000001101
71  //          becomes: 0110100000 and adjust exponent by -5
72  //
73  //   subnormal frac: 1111011011
74  //          becomes: 1011011000 and adjust exponent by -3
75  //
76  // Beware also that, if `frac` is exactly 0 (e.g. if some lowest bits have been lost) then we
77  // need to floor at `Posit::MIN`.
78  if !is_normal {
79    if frac == Int::ZERO {
80      return (Decoded { frac: Int::ONE, exp: Int::MIN >> 1 }, Int::ZERO)
81    }
82    // SAFETY: Just early returned if `frac == 0`.
83    let underflow = unsafe { frac.leading_run_minus_one() };
84    frac = frac << underflow;
85    exponent = exponent.wrapping_sub(underflow as i64);
86  }
87
88  // Represent the exponent as an `exp` in the target type `Int`.
89  //
90  // Beware to clamp it to the range representable in a `Decoded::exp` of type `Int`, otherwise
91  // there may be overflow in more extreme conversions (like f64 → p8).
92  let exponent = exponent.wrapping_add(EXP_BIAS);
93  let exp =
94    if const { Int::BITS < 64 } && exponent > const_as::<Int, i64>(Int::MAX >> 1) {
95      Int::MAX >> 1
96    } else if const { Int::BITS < 64 } && exponent < const_as::<Int, i64>(Int::MIN >> 1) {
97      Int::MIN >> 1
98    } else {
99      const_as::<_, Int>(exponent)
100    };
101
102  (Decoded { exp, frac }, sticky)
103}
104
105/// Extract the mantissa and exponent fields of an [`f64`], and represent them as a
106/// [`Decoded`], plus any sticky bits that have been lost.
107fn decode_finite_f32<
108  const N: u32,
109  const ES: u32,
110  Int: crate::Int,
111>(num: f32) -> (Decoded<N, ES, Int>, Int) {
112  debug_assert!(num.is_finite());
113  // TODO I'm lazy so for I'm just gonna call into [`decode_finite_f64`], since `f32` → `f64` is
114  // lossless; write standalone impl at some point
115  decode_finite_f64(num.into())
116}
117
118impl<
119  const N: u32,
120  const ES: u32,
121  Int: crate::Int,
122> RoundFrom<f32> for Posit<N, ES, Int> {
123  /// Convert an `f32` into a `Posit`, [rounding according to the standard]:
124  ///
125  /// - If the value is any infinity or any NaN, it converts to [`NaR`](Posit::NAR).
126  /// - Otherwise, the float value is rounded (if necessary).
127  ///
128  /// [rounding according to the standard]: https://posithub.org/docs/posit_standard-2.pdf#subsection.6.5
129  fn round_from(value: f32) -> Self {
130    use core::num::FpCategory;
131    match value.classify() {
132      FpCategory::Nan | FpCategory::Infinite => Self::NAR,
133      FpCategory::Zero => Self::ZERO,
134      FpCategory::Normal | FpCategory::Subnormal => {
135        let (decoded, sticky) = decode_finite_f32(value);
136        unsafe { decoded.encode_regular_round(sticky) }
137      }
138    }
139  }
140}
141
142impl<
143  const N: u32,
144  const ES: u32,
145  Int: crate::Int,
146> RoundFrom<f64> for Posit<N, ES, Int> {
147  /// Convert an `f64` into a `Posit`, [rounding according to the standard]:
148  ///
149  /// - If the value is any infinity or any NaN, it converts to [`NaR`](Posit::NAR).
150  /// - Otherwise, the float value is rounded (if necessary).
151  ///
152  /// [rounding according to the standard]: https://posithub.org/docs/posit_standard-2.pdf#subsection.6.5
153  fn round_from(value: f64) -> Self {
154    use core::num::FpCategory;
155    match value.classify() {
156      FpCategory::Nan | FpCategory::Infinite => Self::NAR,
157      FpCategory::Zero => Self::ZERO,
158      FpCategory::Normal | FpCategory::Subnormal => {
159        let (decoded, sticky) = decode_finite_f64(value);
160        unsafe { decoded.encode_regular_round(sticky) }
161      }
162    }
163  }
164}
165
166#[cfg(test)]
167mod tests {
168  use super::*;
169
170  use malachite::rational::Rational;
171  use proptest::prelude::*;
172
173  mod f64 {
174    use super::*;
175
176    /// Aux function: check that `float` is converted to a posit with the correct rounding.
177    fn is_correct_rounded<const N: u32, const ES: u32, Int: crate::Int>(float: f64) -> bool
178    where
179      Rational: From<Decoded<N, ES, Int>> + TryFrom<Posit<N, ES, Int>> + TryFrom<f64>,
180      <Rational as TryFrom<Posit<N, ES, Int>>>::Error: core::fmt::Debug
181    {
182      let posit = Posit::<N, ES, Int>::round_from(float);
183      match Rational::try_from(float) {
184        Ok(exact) => super::rational::is_correct_rounded(exact, posit),
185        Err(_) => posit == Posit::NAR,
186      }
187    }
188
189    #[test]
190    fn zero() {
191      assert_eq!(crate::p8::round_from(0.0f64), crate::p8::ZERO);
192      assert_eq!(crate::p16::round_from(0.0f64), crate::p16::ZERO);
193      assert_eq!(crate::p32::round_from(0.0f64), crate::p32::ZERO);
194      assert_eq!(crate::p64::round_from(0.0f64), crate::p64::ZERO);
195      assert_eq!(Posit::<8, 0, i8>::round_from(0.0f64), Posit::<8, 0, i8>::ZERO);
196      assert_eq!(Posit::<10, 0, i16>::round_from(0.0f64), Posit::<10, 0, i16>::ZERO);
197      assert_eq!(Posit::<10, 1, i16>::round_from(0.0f64), Posit::<10, 1, i16>::ZERO);
198      assert_eq!(Posit::<10, 2, i16>::round_from(0.0f64), Posit::<10, 2, i16>::ZERO);
199      assert_eq!(Posit::<10, 3, i16>::round_from(0.0f64), Posit::<10, 3, i16>::ZERO);
200    }
201
202    #[test]
203    fn one() {
204      assert_eq!(crate::p8::round_from(1.0f64), crate::p8::ONE);
205      assert_eq!(crate::p16::round_from(1.0f64), crate::p16::ONE);
206      assert_eq!(crate::p32::round_from(1.0f64), crate::p32::ONE);
207      assert_eq!(crate::p64::round_from(1.0f64), crate::p64::ONE);
208      assert_eq!(Posit::<8, 0, i8>::round_from(1.0f64), Posit::<8, 0, i8>::ONE);
209      assert_eq!(Posit::<10, 0, i16>::round_from(1.0f64), Posit::<10, 0, i16>::ONE);
210      assert_eq!(Posit::<10, 1, i16>::round_from(1.0f64), Posit::<10, 1, i16>::ONE);
211      assert_eq!(Posit::<10, 2, i16>::round_from(1.0f64), Posit::<10, 2, i16>::ONE);
212      assert_eq!(Posit::<10, 3, i16>::round_from(1.0f64), Posit::<10, 3, i16>::ONE);
213    }
214
215    #[test]
216    fn minus_one() {
217      assert_eq!(crate::p8::round_from(-1.0f64), crate::p8::MINUS_ONE);
218      assert_eq!(crate::p16::round_from(-1.0f64), crate::p16::MINUS_ONE);
219      assert_eq!(crate::p32::round_from(-1.0f64), crate::p32::MINUS_ONE);
220      assert_eq!(crate::p64::round_from(-1.0f64), crate::p64::MINUS_ONE);
221      assert_eq!(Posit::<8, 0, i8>::round_from(-1.0f64), Posit::<8, 0, i8>::MINUS_ONE);
222      assert_eq!(Posit::<10, 0, i16>::round_from(-1.0f64), Posit::<10, 0, i16>::MINUS_ONE);
223      assert_eq!(Posit::<10, 1, i16>::round_from(-1.0f64), Posit::<10, 1, i16>::MINUS_ONE);
224      assert_eq!(Posit::<10, 2, i16>::round_from(-1.0f64), Posit::<10, 2, i16>::MINUS_ONE);
225      assert_eq!(Posit::<10, 3, i16>::round_from(-1.0f64), Posit::<10, 3, i16>::MINUS_ONE);
226    }
227
228    #[test]
229    fn nan() {
230      assert_eq!(crate::p8::round_from(f64::NAN), crate::p8::NAR);
231      assert_eq!(crate::p16::round_from(f64::NAN), crate::p16::NAR);
232      assert_eq!(crate::p32::round_from(f64::NAN), crate::p32::NAR);
233      assert_eq!(crate::p64::round_from(f64::NAN), crate::p64::NAR);
234      assert_eq!(Posit::<8, 0, i8>::round_from(f64::NAN), Posit::<8, 0, i8>::NAR);
235      assert_eq!(Posit::<10, 0, i16>::round_from(f64::NAN), Posit::<10, 0, i16>::NAR);
236      assert_eq!(Posit::<10, 1, i16>::round_from(f64::NAN), Posit::<10, 1, i16>::NAR);
237      assert_eq!(Posit::<10, 2, i16>::round_from(f64::NAN), Posit::<10, 2, i16>::NAR);
238      assert_eq!(Posit::<10, 3, i16>::round_from(f64::NAN), Posit::<10, 3, i16>::NAR);
239    }
240
241    #[test]
242    fn min_positive() {
243      assert_eq!(crate::p8::round_from(f64::MIN_POSITIVE), crate::p8::MIN_POSITIVE);
244      assert_eq!(crate::p16::round_from(f64::MIN_POSITIVE), crate::p16::MIN_POSITIVE);
245      assert_eq!(crate::p32::round_from(f64::MIN_POSITIVE), crate::p32::MIN_POSITIVE);
246      assert_eq!(crate::p64::round_from(f64::MIN_POSITIVE), crate::p64::MIN_POSITIVE);
247      assert_eq!(Posit::<8, 0, i8>::round_from(f64::MIN_POSITIVE), Posit::<8, 0, i8>::MIN_POSITIVE);
248      assert_eq!(Posit::<10, 0, i16>::round_from(f64::MIN_POSITIVE), Posit::<10, 0, i16>::MIN_POSITIVE);
249      assert_eq!(Posit::<10, 1, i16>::round_from(f64::MIN_POSITIVE), Posit::<10, 1, i16>::MIN_POSITIVE);
250      assert_eq!(Posit::<10, 2, i16>::round_from(f64::MIN_POSITIVE), Posit::<10, 2, i16>::MIN_POSITIVE);
251      assert_eq!(Posit::<10, 3, i16>::round_from(f64::MIN_POSITIVE), Posit::<10, 3, i16>::MIN_POSITIVE);
252    }
253
254    #[test]
255    fn max_negative() {
256      assert_eq!(crate::p8::round_from(-f64::MIN_POSITIVE), crate::p8::MAX_NEGATIVE);
257      assert_eq!(crate::p16::round_from(-f64::MIN_POSITIVE), crate::p16::MAX_NEGATIVE);
258      assert_eq!(crate::p32::round_from(-f64::MIN_POSITIVE), crate::p32::MAX_NEGATIVE);
259      assert_eq!(crate::p64::round_from(-f64::MIN_POSITIVE), crate::p64::MAX_NEGATIVE);
260      assert_eq!(Posit::<8, 0, i8>::round_from(-f64::MIN_POSITIVE), Posit::<8, 0, i8>::MAX_NEGATIVE);
261      assert_eq!(Posit::<10, 0, i16>::round_from(-f64::MIN_POSITIVE), Posit::<10, 0, i16>::MAX_NEGATIVE);
262      assert_eq!(Posit::<10, 1, i16>::round_from(-f64::MIN_POSITIVE), Posit::<10, 1, i16>::MAX_NEGATIVE);
263      assert_eq!(Posit::<10, 2, i16>::round_from(-f64::MIN_POSITIVE), Posit::<10, 2, i16>::MAX_NEGATIVE);
264      assert_eq!(Posit::<10, 3, i16>::round_from(-f64::MIN_POSITIVE), Posit::<10, 3, i16>::MAX_NEGATIVE);
265    }
266
267    const PROPTEST_CASES: u32 = if cfg!(debug_assertions) {0x1_0000} else {0x80_0000};
268    proptest!{
269      #![proptest_config(ProptestConfig::with_cases(PROPTEST_CASES))]
270
271      #[test]
272      fn posit_10_0_proptest(float in any::<f64>()) {
273        assert!(is_correct_rounded::<10, 0, i16>(float), "{:?}", float)
274      }
275
276      #[test]
277      fn posit_10_1_proptest(float in any::<f64>()) {
278        assert!(is_correct_rounded::<10, 1, i16>(float), "{:?}", float)
279      }
280
281      #[test]
282      fn posit_10_2_proptest(float in any::<f64>()) {
283        assert!(is_correct_rounded::<10, 2, i16>(float), "{:?}", float)
284      }
285
286      #[test]
287      fn posit_10_3_proptest(float in any::<f64>()) {
288        assert!(is_correct_rounded::<10, 3, i16>(float), "{:?}", float)
289      }
290
291      #[test]
292      fn posit_8_0_proptest(float in any::<f64>()) {
293        assert!(is_correct_rounded::<8, 0, i8>(float), "{:?}", float)
294      }
295
296      #[test]
297      fn p8_proptest(float in any::<f64>()) {
298        assert!(is_correct_rounded::<8, 2, i8>(float), "{:?}", float)
299      }
300
301      #[test]
302      fn p16_proptest(float in any::<f64>()) {
303        assert!(is_correct_rounded::<16, 2, i16>(float), "{:?}", float)
304      }
305
306      #[test]
307      fn p32_proptest(float in any::<f64>()) {
308        assert!(is_correct_rounded::<32, 2, i32>(float), "{:?}", float)
309      }
310
311      #[test]
312      fn p64_proptest(float in any::<f64>()) {
313        assert!(is_correct_rounded::<64, 2, i64>(float), "{:?}", float)
314      }
315    }
316  }
317
318  mod f32 {
319    use super::*;
320
321    /// Aux function: check that `float` is converted to a posit with the correct rounding.
322    fn is_correct_rounded<const N: u32, const ES: u32, Int: crate::Int>(float: f32) -> bool
323    where
324      Rational: From<Decoded<N, ES, Int>> + TryFrom<Posit<N, ES, Int>> + TryFrom<f32>,
325      <Rational as TryFrom<Posit<N, ES, Int>>>::Error: core::fmt::Debug
326    {
327      let posit = Posit::<N, ES, Int>::round_from(float);
328      match Rational::try_from(float) {
329        Ok(exact) => super::rational::is_correct_rounded(exact, posit),
330        Err(_) => posit == Posit::NAR,
331      }
332    }
333
334    #[test]
335    fn zero() {
336      assert_eq!(crate::p8::round_from(0.0f32), crate::p8::ZERO);
337      assert_eq!(crate::p16::round_from(0.0f32), crate::p16::ZERO);
338      assert_eq!(crate::p32::round_from(0.0f32), crate::p32::ZERO);
339      assert_eq!(crate::p64::round_from(0.0f32), crate::p64::ZERO);
340      assert_eq!(Posit::<8, 0, i8>::round_from(0.0f32), Posit::<8, 0, i8>::ZERO);
341      assert_eq!(Posit::<10, 0, i16>::round_from(0.0f32), Posit::<10, 0, i16>::ZERO);
342      assert_eq!(Posit::<10, 1, i16>::round_from(0.0f32), Posit::<10, 1, i16>::ZERO);
343      assert_eq!(Posit::<10, 2, i16>::round_from(0.0f32), Posit::<10, 2, i16>::ZERO);
344      assert_eq!(Posit::<10, 3, i16>::round_from(0.0f32), Posit::<10, 3, i16>::ZERO);
345    }
346
347    #[test]
348    fn one() {
349      assert_eq!(crate::p8::round_from(1.0f32), crate::p8::ONE);
350      assert_eq!(crate::p16::round_from(1.0f32), crate::p16::ONE);
351      assert_eq!(crate::p32::round_from(1.0f32), crate::p32::ONE);
352      assert_eq!(crate::p64::round_from(1.0f32), crate::p64::ONE);
353      assert_eq!(Posit::<8, 0, i8>::round_from(1.0f32), Posit::<8, 0, i8>::ONE);
354      assert_eq!(Posit::<10, 0, i16>::round_from(1.0f32), Posit::<10, 0, i16>::ONE);
355      assert_eq!(Posit::<10, 1, i16>::round_from(1.0f32), Posit::<10, 1, i16>::ONE);
356      assert_eq!(Posit::<10, 2, i16>::round_from(1.0f32), Posit::<10, 2, i16>::ONE);
357      assert_eq!(Posit::<10, 3, i16>::round_from(1.0f32), Posit::<10, 3, i16>::ONE);
358    }
359
360    #[test]
361    fn minus_one() {
362      assert_eq!(crate::p8::round_from(-1.0f32), crate::p8::MINUS_ONE);
363      assert_eq!(crate::p16::round_from(-1.0f32), crate::p16::MINUS_ONE);
364      assert_eq!(crate::p32::round_from(-1.0f32), crate::p32::MINUS_ONE);
365      assert_eq!(crate::p64::round_from(-1.0f32), crate::p64::MINUS_ONE);
366      assert_eq!(Posit::<8, 0, i8>::round_from(-1.0f32), Posit::<8, 0, i8>::MINUS_ONE);
367      assert_eq!(Posit::<10, 0, i16>::round_from(-1.0f32), Posit::<10, 0, i16>::MINUS_ONE);
368      assert_eq!(Posit::<10, 1, i16>::round_from(-1.0f32), Posit::<10, 1, i16>::MINUS_ONE);
369      assert_eq!(Posit::<10, 2, i16>::round_from(-1.0f32), Posit::<10, 2, i16>::MINUS_ONE);
370      assert_eq!(Posit::<10, 3, i16>::round_from(-1.0f32), Posit::<10, 3, i16>::MINUS_ONE);
371    }
372
373    #[test]
374    fn nan() {
375      assert_eq!(crate::p8::round_from(f32::NAN), crate::p8::NAR);
376      assert_eq!(crate::p16::round_from(f32::NAN), crate::p16::NAR);
377      assert_eq!(crate::p32::round_from(f32::NAN), crate::p32::NAR);
378      assert_eq!(crate::p64::round_from(f32::NAN), crate::p64::NAR);
379      assert_eq!(Posit::<8, 0, i8>::round_from(f32::NAN), Posit::<8, 0, i8>::NAR);
380      assert_eq!(Posit::<10, 0, i16>::round_from(f32::NAN), Posit::<10, 0, i16>::NAR);
381      assert_eq!(Posit::<10, 1, i16>::round_from(f32::NAN), Posit::<10, 1, i16>::NAR);
382      assert_eq!(Posit::<10, 2, i16>::round_from(f32::NAN), Posit::<10, 2, i16>::NAR);
383      assert_eq!(Posit::<10, 3, i16>::round_from(f32::NAN), Posit::<10, 3, i16>::NAR);
384    }
385
386    #[test]
387    fn min_positive() {
388      assert_eq!(crate::p8::round_from(f32::MIN_POSITIVE), crate::p8::MIN_POSITIVE);
389      assert_eq!(crate::p16::round_from(f32::MIN_POSITIVE), crate::p16::MIN_POSITIVE);
390      assert_eq!(crate::p32::round_from(f32::MIN_POSITIVE), crate::p32::MIN_POSITIVE);
391      // assert_eq!(crate::p64::round_from(f32::MIN_POSITIVE), crate::p64::MIN_POSITIVE);
392      assert_eq!(Posit::<8, 0, i8>::round_from(f32::MIN_POSITIVE), Posit::<8, 0, i8>::MIN_POSITIVE);
393      assert_eq!(Posit::<10, 0, i16>::round_from(f32::MIN_POSITIVE), Posit::<10, 0, i16>::MIN_POSITIVE);
394      assert_eq!(Posit::<10, 1, i16>::round_from(f32::MIN_POSITIVE), Posit::<10, 1, i16>::MIN_POSITIVE);
395      assert_eq!(Posit::<10, 2, i16>::round_from(f32::MIN_POSITIVE), Posit::<10, 2, i16>::MIN_POSITIVE);
396      assert_eq!(Posit::<10, 3, i16>::round_from(f32::MIN_POSITIVE), Posit::<10, 3, i16>::MIN_POSITIVE);
397    }
398
399    #[test]
400    fn max_negative() {
401      assert_eq!(crate::p8::round_from(-f32::MIN_POSITIVE), crate::p8::MAX_NEGATIVE);
402      assert_eq!(crate::p16::round_from(-f32::MIN_POSITIVE), crate::p16::MAX_NEGATIVE);
403      assert_eq!(crate::p32::round_from(-f32::MIN_POSITIVE), crate::p32::MAX_NEGATIVE);
404      // assert_eq!(crate::p64::round_from(-f32::MIN_POSITIVE), crate::p64::MAX_NEGATIVE);
405      assert_eq!(Posit::<8, 0, i8>::round_from(-f32::MIN_POSITIVE), Posit::<8, 0, i8>::MAX_NEGATIVE);
406      assert_eq!(Posit::<10, 0, i16>::round_from(-f32::MIN_POSITIVE), Posit::<10, 0, i16>::MAX_NEGATIVE);
407      assert_eq!(Posit::<10, 1, i16>::round_from(-f32::MIN_POSITIVE), Posit::<10, 1, i16>::MAX_NEGATIVE);
408      assert_eq!(Posit::<10, 2, i16>::round_from(-f32::MIN_POSITIVE), Posit::<10, 2, i16>::MAX_NEGATIVE);
409      assert_eq!(Posit::<10, 3, i16>::round_from(-f32::MIN_POSITIVE), Posit::<10, 3, i16>::MAX_NEGATIVE);
410    }
411
412    const PROPTEST_CASES: u32 = if cfg!(debug_assertions) {0x1_0000} else {0x80_0000};
413    proptest!{
414      #![proptest_config(ProptestConfig::with_cases(PROPTEST_CASES))]
415
416      #[test]
417      fn posit_10_0_proptest(float in any::<f32>()) {
418        assert!(is_correct_rounded::<10, 0, i16>(float), "{:?}", float)
419      }
420
421      #[test]
422      fn posit_10_1_proptest(float in any::<f32>()) {
423        assert!(is_correct_rounded::<10, 1, i16>(float), "{:?}", float)
424      }
425
426      #[test]
427      fn posit_10_2_proptest(float in any::<f32>()) {
428        assert!(is_correct_rounded::<10, 2, i16>(float), "{:?}", float)
429      }
430
431      #[test]
432      fn posit_10_3_proptest(float in any::<f32>()) {
433        assert!(is_correct_rounded::<10, 3, i16>(float), "{:?}", float)
434      }
435
436      #[test]
437      fn posit_8_0_proptest(float in any::<f32>()) {
438        assert!(is_correct_rounded::<8, 0, i8>(float), "{:?}", float)
439      }
440
441      #[test]
442      fn p8_proptest(float in any::<f32>()) {
443        assert!(is_correct_rounded::<8, 2, i8>(float), "{:?}", float)
444      }
445
446      #[test]
447      fn p16_proptest(float in any::<f32>()) {
448        assert!(is_correct_rounded::<16, 2, i16>(float), "{:?}", float)
449      }
450
451      #[test]
452      fn p32_proptest(float in any::<f32>()) {
453        assert!(is_correct_rounded::<32, 2, i32>(float), "{:?}", float)
454      }
455
456      #[test]
457      fn p64_proptest(float in any::<f32>()) {
458        assert!(is_correct_rounded::<64, 2, i64>(float), "{:?}", float)
459      }
460    }
461  }
462
463  // TODO remove code duplication in tests...?
464}