Skip to main content

proptest/
num.rs

1//-
2// Copyright 2017, 2018 Jason Lingle
3//
4// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7// option. This file may not be copied, modified, or distributed
8// except according to those terms.
9
10//! Strategies to generate numeric values (as opposed to integers used as bit
11//! fields).
12//!
13//! All strategies in this module shrink by binary searching towards 0.
14
15mod float_samplers;
16
17use crate::test_runner::TestRunner;
18use rand::distr::uniform::{SampleUniform, Uniform};
19use rand::distr::{Distribution, StandardUniform};
20
21/// Generate a random value of `X`, sampled uniformly from the half
22/// open range `[low, high)` (excluding `high`). Panics if `low >= high`.
23pub(crate) fn sample_uniform<X: SampleUniform>(
24    run: &mut TestRunner,
25    start: X,
26    end: X,
27) -> X {
28    Uniform::new(start, end).expect("not uniform").sample(run.rng())
29}
30
31/// Generate a random value of `X`, sampled uniformly from the closed
32/// range `[low, high]` (inclusive). Panics if `low > high`.
33pub fn sample_uniform_incl<X: SampleUniform>(
34    run: &mut TestRunner,
35    start: X,
36    end: X,
37) -> X {
38    Uniform::new_inclusive(start, end).expect("not uniform").sample(run.rng())
39}
40
41macro_rules! sample_uniform {
42    ($name: ident, $incl:ident, $from:ty, $to:ty) => {
43        fn $name<X>(
44            run: &mut TestRunner,
45            start: $to,
46            end: $to,
47        ) -> $to {
48            Uniform::<$from>::new(start as $from, end as $from).expect("not uniform").sample(run.rng()) as $to
49        }
50
51        fn $incl<X>(
52            run: &mut TestRunner,
53            start: $to,
54            end: $to,
55        ) -> $to {
56            Uniform::<$from>::new_inclusive(start as $from, end as $from).expect("not uniform").sample(run.rng()) as $to
57        }        
58    }
59}
60
61#[cfg(target_pointer_width = "64")]
62sample_uniform!(usize_sample_uniform, usize_sample_uniform_incl, u64, usize);
63#[cfg(target_pointer_width = "32")]
64sample_uniform!(usize_sample_uniform, usize_sample_uniform_incl, u32, usize);
65#[cfg(target_pointer_width = "16")]
66sample_uniform!(usize_sample_uniform, usize_sample_uniform_incl, u16, usize);
67
68#[cfg(target_pointer_width = "64")]
69sample_uniform!(isize_sample_uniform, isize_sample_uniform_incl, i64, isize);
70#[cfg(target_pointer_width = "32")]
71sample_uniform!(isize_sample_uniform, isize_sample_uniform_incl, i32, isize);
72#[cfg(target_pointer_width = "16")]
73sample_uniform!(isize_sample_uniform, isize_sample_uniform_incl, i16, isize);
74
75macro_rules! supported_int_any {
76    ($runner:ident, $typ:ty) => {
77        $runner.rng().random()
78    };
79}
80
81#[cfg(target_pointer_width = "64")]
82macro_rules! unsupported_int_any {
83    ($runner:ident, $typ:ty) => {
84        $runner.rng().next_u64() as $typ
85    };
86}
87
88#[cfg(not(target_pointer_width = "64"))]
89macro_rules! unsupported_int_any {
90    ($runner:ident, $typ:ty) => {
91        $runner.rng().next_u32() as $typ
92    };
93}
94
95macro_rules! int_any {
96    ($typ: ident, $int_any: ident) => {
97        /// Type of the `ANY` constant.
98        #[derive(Clone, Copy, Debug)]
99        #[must_use = "strategies do nothing unless used"]
100        pub struct Any(());
101        /// Generates integers with completely arbitrary values, uniformly
102        /// distributed over the whole range.
103        pub const ANY: Any = Any(());
104
105        impl Strategy for Any {
106            type Tree = BinarySearch;
107            type Value = $typ;
108
109            fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
110                Ok(BinarySearch::new($int_any!(runner, $typ)))
111            }
112        }
113    };
114}
115
116macro_rules! numeric_api {
117    ($typ:ident, $epsilon:expr) => {
118        numeric_api!($typ, $typ, $epsilon);
119    };
120    ($typ:ident, $sample_typ:ty, $epsilon:expr) => {
121        numeric_api!($typ, $sample_typ, $epsilon, sample_uniform, sample_uniform_incl);
122    };
123    ($typ:ident, $epsilon:expr, $uniform:ident, $incl:ident) => {
124        numeric_api!($typ, $typ, $epsilon, $uniform, $incl);
125    };
126    ($typ:ident, $sample_typ:ty, $epsilon:expr, $uniform:ident, $incl:ident) => {
127        impl Strategy for ::core::ops::Range<$typ> {
128            type Tree = BinarySearch;
129            type Value = $typ;
130
131            fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
132                if self.is_empty() {
133                    panic!(
134                        "Invalid use of empty range {}..{}.",
135                        self.start, self.end
136                    );
137                }
138
139                Ok(BinarySearch::new_clamped(
140                    self.start,
141                    $crate::num::$uniform::<$sample_typ>(
142                        runner,
143                        self.start.into(),
144                        self.end.into(),
145                    )
146                    .into(),
147                    self.end - $epsilon,
148                ))
149            }
150        }
151
152        impl Strategy for ::core::ops::RangeInclusive<$typ> {
153            type Tree = BinarySearch;
154            type Value = $typ;
155
156            fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
157                if self.is_empty() {
158                    panic!(
159                        "Invalid use of empty range {}..={}.",
160                        self.start(),
161                        self.end()
162                    );
163                }
164
165                Ok(BinarySearch::new_clamped(
166                    *self.start(),
167                    $crate::num::$incl::<$sample_typ>(
168                        runner,
169                        (*self.start()).into(),
170                        (*self.end()).into(),
171                    )
172                    .into(),
173                    *self.end(),
174                ))
175            }
176        }
177
178        impl Strategy for ::core::ops::RangeFrom<$typ> {
179            type Tree = BinarySearch;
180            type Value = $typ;
181
182            fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
183                Ok(BinarySearch::new_clamped(
184                    self.start,
185                    $crate::num::$incl::<$sample_typ>(
186                        runner,
187                        self.start.into(),
188                        <$typ>::MAX.into(),
189                    )
190                    .into(),
191                    <$typ>::MAX,
192                ))
193            }
194        }
195
196        impl Strategy for ::core::ops::RangeTo<$typ> {
197            type Tree = BinarySearch;
198            type Value = $typ;
199
200            fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
201                Ok(BinarySearch::new_clamped(
202                    <$typ>::MIN,
203                    $crate::num::$uniform::<$sample_typ>(
204                        runner,
205                        <$typ>::MIN.into(),
206                        self.end.into(),
207                    )
208                    .into(),
209                    self.end,
210                ))
211            }
212        }
213
214        impl Strategy for ::core::ops::RangeToInclusive<$typ> {
215            type Tree = BinarySearch;
216            type Value = $typ;
217
218            fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
219                Ok(BinarySearch::new_clamped(
220                    <$typ>::MIN,
221                    $crate::num::$incl::<$sample_typ>(
222                        runner,
223                        <$typ>::MIN.into(),
224                        self.end.into(),
225                    )
226                    .into(),
227                    self.end,
228                ))
229            }
230        }
231    };
232}
233
234macro_rules! signed_integer_bin_search {
235    ($typ:ident) => {
236        signed_integer_bin_search!($typ, supported_int_any, sample_uniform, sample_uniform_incl);
237    };
238    ($typ:ident, $int_any: ident, $uniform: ident, $incl: ident) => {
239        #[allow(missing_docs)]
240        pub mod $typ {
241            #[allow(unused_imports)]
242            use rand::{Rng, RngCore};
243
244            use crate::strategy::*;
245            use crate::test_runner::TestRunner;
246
247            int_any!($typ, $int_any);
248
249            /// Shrinks an integer towards 0, using binary search to find
250            /// boundary points.
251            #[derive(Clone, Copy, Debug)]
252            pub struct BinarySearch {
253                lo: $typ,
254                curr: $typ,
255                hi: $typ,
256            }
257            impl BinarySearch {
258                /// Creates a new binary searcher starting at the given value.
259                pub fn new(start: $typ) -> Self {
260                    BinarySearch {
261                        lo: 0,
262                        curr: start,
263                        hi: start,
264                    }
265                }
266
267                /// Creates a new binary searcher which will not produce values
268                /// on the other side of `lo` or `hi` from `start`. `lo` is
269                /// inclusive, `hi` is exclusive.
270                fn new_clamped(lo: $typ, start: $typ, hi: $typ) -> Self {
271                    use core::cmp::{max, min};
272
273                    BinarySearch {
274                        lo: if start < 0 {
275                            min(0, hi - 1)
276                        } else {
277                            max(0, lo)
278                        },
279                        hi: start,
280                        curr: start,
281                    }
282                }
283
284                fn reposition(&mut self) -> bool {
285                    // Won't ever overflow since lo starts at 0 and advances
286                    // towards hi.
287                    let interval = self.hi - self.lo;
288                    let new_mid = self.lo + interval / 2;
289
290                    if new_mid == self.curr {
291                        false
292                    } else {
293                        self.curr = new_mid;
294                        true
295                    }
296                }
297
298                fn magnitude_greater(lhs: $typ, rhs: $typ) -> bool {
299                    if 0 == lhs {
300                        false
301                    } else if lhs < 0 {
302                        lhs < rhs
303                    } else {
304                        lhs > rhs
305                    }
306                }
307            }
308            impl ValueTree for BinarySearch {
309                type Value = $typ;
310
311                fn current(&self) -> $typ {
312                    self.curr
313                }
314
315                fn simplify(&mut self) -> bool {
316                    if !BinarySearch::magnitude_greater(self.hi, self.lo) {
317                        return false;
318                    }
319
320                    self.hi = self.curr;
321                    self.reposition()
322                }
323
324                fn complicate(&mut self) -> bool {
325                    if !BinarySearch::magnitude_greater(self.hi, self.lo) {
326                        return false;
327                    }
328
329                    self.lo = self.curr + if self.hi < 0 { -1 } else { 1 };
330
331                    self.reposition()
332                }
333            }
334
335            numeric_api!($typ, 1, $uniform, $incl);
336        }
337    };
338}
339
340macro_rules! unsigned_integer_bin_search {
341    ($typ:ident) => {
342        unsigned_integer_bin_search!($typ, supported_int_any, sample_uniform, sample_uniform_incl);
343    };
344    ($typ:ident, $int_any: ident, $uniform: ident, $incl: ident) => {
345        #[allow(missing_docs)]
346        pub mod $typ {
347            #[allow(unused_imports)]
348            use rand::{Rng, RngCore};
349
350            use crate::strategy::*;
351            use crate::test_runner::TestRunner;
352
353            int_any!($typ, $int_any);
354
355            /// Shrinks an integer towards 0, using binary search to find
356            /// boundary points.
357            #[derive(Clone, Copy, Debug)]
358            pub struct BinarySearch {
359                lo: $typ,
360                curr: $typ,
361                hi: $typ,
362            }
363            impl BinarySearch {
364                /// Creates a new binary searcher starting at the given value.
365                pub fn new(start: $typ) -> Self {
366                    BinarySearch {
367                        lo: 0,
368                        curr: start,
369                        hi: start,
370                    }
371                }
372
373                /// Creates a new binary searcher which will not search below
374                /// the given `lo` value.
375                fn new_clamped(lo: $typ, start: $typ, _hi: $typ) -> Self {
376                    BinarySearch {
377                        lo: lo,
378                        curr: start,
379                        hi: start,
380                    }
381                }
382
383                /// Creates a new binary searcher which will not search below
384                /// the given `lo` value.
385                pub fn new_above(lo: $typ, start: $typ) -> Self {
386                    BinarySearch::new_clamped(lo, start, start)
387                }
388
389                fn reposition(&mut self) -> bool {
390                    let interval = self.hi - self.lo;
391                    let new_mid = self.lo + interval / 2;
392
393                    if new_mid == self.curr {
394                        false
395                    } else {
396                        self.curr = new_mid;
397                        true
398                    }
399                }
400            }
401            impl ValueTree for BinarySearch {
402                type Value = $typ;
403
404                fn current(&self) -> $typ {
405                    self.curr
406                }
407
408                fn simplify(&mut self) -> bool {
409                    if self.hi <= self.lo {
410                        return false;
411                    }
412
413                    self.hi = self.curr;
414                    self.reposition()
415                }
416
417                fn complicate(&mut self) -> bool {
418                    if self.hi <= self.lo {
419                        return false;
420                    }
421
422                    self.lo = self.curr + 1;
423                    self.reposition()
424                }
425            }
426
427            numeric_api!($typ, 1, $uniform, $incl);
428        }
429    };
430}
431
432signed_integer_bin_search!(i8);
433signed_integer_bin_search!(i16);
434signed_integer_bin_search!(i32);
435signed_integer_bin_search!(i64);
436signed_integer_bin_search!(i128);
437signed_integer_bin_search!(isize, unsupported_int_any, isize_sample_uniform, isize_sample_uniform_incl);
438unsigned_integer_bin_search!(u8);
439unsigned_integer_bin_search!(u16);
440unsigned_integer_bin_search!(u32);
441unsigned_integer_bin_search!(u64);
442unsigned_integer_bin_search!(u128);
443unsigned_integer_bin_search!(usize, unsupported_int_any, usize_sample_uniform, usize_sample_uniform_incl);
444
445bitflags! {
446    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
447    pub(crate) struct FloatTypes: u32 {
448        const POSITIVE          = 0b0000_0001;
449        const NEGATIVE          = 0b0000_0010;
450        const NORMAL            = 0b0000_0100;
451        const SUBNORMAL         = 0b0000_1000;
452        const ZERO              = 0b0001_0000;
453        const INFINITE          = 0b0010_0000;
454        const QUIET_NAN         = 0b0100_0000;
455        const SIGNALING_NAN     = 0b1000_0000;
456        const ANY =
457            Self::POSITIVE.bits() |
458            Self::NEGATIVE.bits() |
459            Self::NORMAL.bits() |
460            Self::SUBNORMAL.bits() |
461            Self::ZERO.bits() |
462            Self::INFINITE.bits() |
463            Self::QUIET_NAN.bits();
464    }
465}
466
467impl FloatTypes {
468    fn normalise(mut self) -> Self {
469        if !self.intersects(FloatTypes::POSITIVE | FloatTypes::NEGATIVE) {
470            self |= FloatTypes::POSITIVE;
471        }
472
473        if !self.intersects(
474            FloatTypes::NORMAL
475                | FloatTypes::SUBNORMAL
476                | FloatTypes::ZERO
477                | FloatTypes::INFINITE
478                | FloatTypes::QUIET_NAN
479                | FloatTypes::SIGNALING_NAN,
480        ) {
481            self |= FloatTypes::NORMAL;
482        }
483        self
484    }
485}
486
487trait FloatLayout
488where
489    StandardUniform: Distribution<Self::Bits>,
490{
491    type Bits: Copy;
492
493    const SIGN_MASK: Self::Bits;
494    const EXP_MASK: Self::Bits;
495    const EXP_ZERO: Self::Bits;
496    const MANTISSA_MASK: Self::Bits;
497}
498
499#[cfg(feature = "f16")]
500impl FloatLayout for f16 {
501    type Bits = u16;
502
503    const SIGN_MASK: u16 = 0x8000;
504    const EXP_MASK: u16 = 0x7c00;
505    const EXP_ZERO: u16 = f16::to_bits(1.0);
506    const MANTISSA_MASK: u16 = !(Self::SIGN_MASK | Self::EXP_MASK);
507}
508
509impl FloatLayout for f32 {
510    type Bits = u32;
511
512    const SIGN_MASK: u32 = 0x8000_0000;
513    const EXP_MASK: u32 = 0x7F80_0000;
514    const EXP_ZERO: u32 = 0x3F80_0000;
515    const MANTISSA_MASK: u32 = 0x007F_FFFF;
516}
517
518impl FloatLayout for f64 {
519    type Bits = u64;
520
521    const SIGN_MASK: u64 = 0x8000_0000_0000_0000;
522    const EXP_MASK: u64 = 0x7FF0_0000_0000_0000;
523    const EXP_ZERO: u64 = 0x3FF0_0000_0000_0000;
524    const MANTISSA_MASK: u64 = 0x000F_FFFF_FFFF_FFFF;
525}
526
527macro_rules! float_any {
528    ($typ:ident) => {
529        /// Strategies which produce floating-point values from particular
530        /// classes. See the various `Any`-typed constants in this module.
531        ///
532        /// Note that this usage is fairly advanced and primarily useful to
533        /// implementors of algorithms that need to handle wild values in a
534        /// particular way. For testing things like graphics processing or game
535        /// physics, simply using ranges (e.g., `-1.0..2.0`) will often be more
536        /// practical.
537        ///
538        /// `Any` can be OR'ed to combine multiple classes. For example,
539        /// `POSITIVE | INFINITE` will generate arbitrary positive, non-NaN
540        /// floats, including positive infinity (but not negative infinity, of
541        /// course).
542        ///
543        /// If neither `POSITIVE` nor `NEGATIVE` has been OR'ed into an `Any`
544        /// but a type to be generated requires a sign, `POSITIVE` is assumed.
545        /// If no classes are OR'ed into an `Any` (i.e., only `POSITIVE` and/or
546        /// `NEGATIVE` are given), `NORMAL` is assumed.
547        ///
548        /// The various float classes are assigned fixed weights for generation
549        /// which are believed to be reasonable for most applications. Roughly:
550        ///
551        /// - If `POSITIVE | NEGATIVE`, the sign is evenly distributed between
552        ///   both options.
553        ///
554        /// - Classes are weighted as follows, in descending order:
555        ///   `NORMAL` > `ZERO` > `SUBNORMAL` > `INFINITE` > `QUIET_NAN` =
556        ///   `SIGNALING_NAN`.
557        #[derive(Clone, Copy, Debug)]
558        #[must_use = "strategies do nothing unless used"]
559        pub struct Any(FloatTypes);
560
561        #[cfg(test)]
562        impl Any {
563            pub(crate) fn from_bits(bits: u32) -> Self {
564                Any(FloatTypes::from_bits_truncate(bits))
565            }
566
567            pub(crate) fn normal_bits(&self) -> FloatTypes {
568                self.0.normalise()
569            }
570        }
571
572        impl ops::BitOr for Any {
573            type Output = Self;
574
575            fn bitor(self, rhs: Self) -> Self {
576                Any(self.0 | rhs.0)
577            }
578        }
579
580        impl ops::BitOrAssign for Any {
581            fn bitor_assign(&mut self, rhs: Self) {
582                self.0 |= rhs.0
583            }
584        }
585
586        /// Generates positive floats
587        ///
588        /// By itself, implies the `NORMAL` class, unless another class is
589        /// OR'ed in. That is, using `POSITIVE` as a strategy by itself will
590        /// generate arbitrary values between the type's `MIN_POSITIVE` and
591        /// `MAX`, while `POSITIVE | INFINITE` would only allow generating
592        /// positive infinity.
593        pub const POSITIVE: Any = Any(FloatTypes::POSITIVE);
594        /// Generates negative floats.
595        ///
596        /// By itself, implies the `NORMAL` class, unless another class is
597        /// OR'ed in. That is, using `POSITIVE` as a strategy by itself will
598        /// generate arbitrary values between the type's `MIN` and
599        /// `-MIN_POSITIVE`, while `NEGATIVE | INFINITE` would only allow
600        /// generating positive infinity.
601        pub const NEGATIVE: Any = Any(FloatTypes::NEGATIVE);
602        /// Generates "normal" floats.
603        ///
604        /// These are finite values where the first bit of the mantissa is an
605        /// implied `1`. When positive, this represents the range
606        /// `MIN_POSITIVE` through `MAX`, both inclusive.
607        ///
608        /// Generated values are uniform over the discrete floating-point
609        /// space, which means the numeric distribution is an inverse
610        /// exponential step function. For example, values between 1.0 and 2.0
611        /// are generated with the same frequency as values between 2.0 and
612        /// 4.0, even though the latter covers twice the numeric range.
613        ///
614        /// If neither `POSITIVE` nor `NEGATIVE` is OR'ed with this constant,
615        /// `POSITIVE` is implied.
616        pub const NORMAL: Any = Any(FloatTypes::NORMAL);
617        /// Generates subnormal floats.
618        ///
619        /// These are finite non-zero values where the first bit of the
620        /// mantissa is not an implied zero. When positive, this represents the
621        /// range `MIN`, inclusive, through `MIN_POSITIVE`, exclusive.
622        ///
623        /// Subnormals are generated with a uniform distribution both in terms
624        /// of discrete floating-point space and numerically.
625        ///
626        /// If neither `POSITIVE` nor `NEGATIVE` is OR'ed with this constant,
627        /// `POSITIVE` is implied.
628        pub const SUBNORMAL: Any = Any(FloatTypes::SUBNORMAL);
629        /// Generates zero-valued floats.
630        ///
631        /// Note that IEEE floats support both positive and negative zero, so
632        /// this class does interact with the sign flags.
633        ///
634        /// If neither `POSITIVE` nor `NEGATIVE` is OR'ed with this constant,
635        /// `POSITIVE` is implied.
636        pub const ZERO: Any = Any(FloatTypes::ZERO);
637        /// Generates infinity floats.
638        ///
639        /// If neither `POSITIVE` nor `NEGATIVE` is OR'ed with this constant,
640        /// `POSITIVE` is implied.
641        pub const INFINITE: Any = Any(FloatTypes::INFINITE);
642        /// Generates "Quiet NaN" floats.
643        ///
644        /// Operations on quiet NaNs generally simply propagate the NaN rather
645        /// than invoke any exception mechanism.
646        ///
647        /// The payload of the NaN is uniformly distributed over the possible
648        /// values which safe Rust allows, including the sign bit (as
649        /// controlled by `POSITIVE` and `NEGATIVE`).
650        ///
651        /// Note however that in Rust 1.23.0 and earlier, this constitutes only
652        /// one particular payload due to apparent issues with particular MIPS
653        /// and PA-RISC processors which fail to implement IEEE 754-2008
654        /// correctly.
655        ///
656        /// On Rust 1.24.0 and later, this does produce arbitrary payloads as
657        /// documented.
658        ///
659        /// On platforms where the CPU and the IEEE standard disagree on the
660        /// format of a quiet NaN, values generated conform to the hardware's
661        /// expectations.
662        pub const QUIET_NAN: Any = Any(FloatTypes::QUIET_NAN);
663        /// Generates "Signaling NaN" floats if allowed by the platform.
664        ///
665        /// On most platforms, signalling NaNs by default behave the same as
666        /// quiet NaNs, but it is possible to configure the OS or CPU to raise
667        /// an asynchronous exception if an operation is performed on a
668        /// signalling NaN.
669        ///
670        /// In Rust 1.23.0 and earlier, this silently behaves the same as
671        /// [`QUIET_NAN`](const.QUIET_NAN.html).
672        ///
673        /// On platforms where the CPU and the IEEE standard disagree on the
674        /// format of a quiet NaN, values generated conform to the hardware's
675        /// expectations.
676        ///
677        /// Note that certain platforms — most notably, x86/AMD64 — allow the
678        /// architecture to turn a signalling NaN into a quiet NaN with the
679        /// same payload. Whether this happens can depend on what registers the
680        /// compiler decides to use to pass the value around, what CPU flags
681        /// are set, and what compiler settings are in use.
682        pub const SIGNALING_NAN: Any = Any(FloatTypes::SIGNALING_NAN);
683
684        /// Generates literally arbitrary floating-point values, including
685        /// infinities and quiet NaNs (but not signaling NaNs).
686        ///
687        /// Equivalent to `POSITIVE | NEGATIVE | NORMAL | SUBNORMAL | ZERO |
688        /// INFINITE | QUIET_NAN`.
689        ///
690        /// See [`SIGNALING_NAN`](const.SIGNALING_NAN.html) if you also want to
691        /// generate signalling NaNs. This signalling NaNs are not included by
692        /// default since in most contexts they either make no difference, or
693        /// if the process enabled the relevant CPU mode, result in
694        /// hardware-triggered exceptions that usually just abort the process.
695        ///
696        /// Before proptest 0.4.1, this erroneously generated values in the
697        /// range 0.0..1.0.
698        pub const ANY: Any = Any(FloatTypes::ANY);
699
700        impl Strategy for Any {
701            type Tree = BinarySearch;
702            type Value = $typ;
703
704            fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
705                let flags = self.0.normalise();
706                let sign_mask = if flags.contains(FloatTypes::NEGATIVE) {
707                    $typ::SIGN_MASK
708                } else {
709                    0
710                };
711                let sign_or = if flags.contains(FloatTypes::POSITIVE) {
712                    0
713                } else {
714                    $typ::SIGN_MASK
715                };
716
717                macro_rules! weight {
718                    ($case:ident, $weight:expr) => {
719                        if flags.contains(FloatTypes::$case) {
720                            $weight
721                        } else {
722                            0
723                        }
724                    }
725                }
726
727                // A few CPUs disagree with IEEE about the meaning of the
728                // signalling bit. Assume the `NAN` constant is a quiet NaN as
729                // interpreted by the hardware and generate values based on
730                // that.
731                let quiet_or = $typ::NAN.to_bits() &
732                    ($typ::EXP_MASK | ($typ::EXP_MASK >> 1));
733                let signaling_or = (quiet_or ^ ($typ::EXP_MASK >> 1)) |
734                    $typ::EXP_MASK;
735
736                let (class_mask, class_or, allow_edge_exp, allow_zero_mant) =
737                    prop_oneof![
738                        weight!(NORMAL, 20) => Just(
739                            ($typ::EXP_MASK | $typ::MANTISSA_MASK, 0,
740                             false, true)),
741                        weight!(SUBNORMAL, 3) => Just(
742                            ($typ::MANTISSA_MASK, 0, true, false)),
743                        weight!(ZERO, 4) => Just(
744                            (0, 0, true, true)),
745                        weight!(INFINITE, 2) => Just(
746                            (0, $typ::EXP_MASK, true, true)),
747                        weight!(QUIET_NAN, 1) => Just(
748                            ($typ::MANTISSA_MASK >> 1, quiet_or,
749                             true, false)),
750                        weight!(SIGNALING_NAN, 1) => Just(
751                            ($typ::MANTISSA_MASK >> 1, signaling_or,
752                             true, false)),
753                    ].new_tree(runner)?.current();
754
755                let mut generated_value: <$typ as FloatLayout>::Bits =
756                    runner.rng().random();
757                generated_value &= sign_mask | class_mask;
758                generated_value |= sign_or | class_or;
759                let exp = generated_value & $typ::EXP_MASK;
760                if !allow_edge_exp && (0 == exp || $typ::EXP_MASK == exp) {
761                    generated_value &= !$typ::EXP_MASK;
762                    generated_value |= $typ::EXP_ZERO;
763                }
764                if !allow_zero_mant &&
765                    0 == generated_value & $typ::MANTISSA_MASK
766                {
767                    generated_value |= 1;
768                }
769
770                Ok(BinarySearch::new_with_types(
771                    $typ::from_bits(generated_value), flags))
772            }
773        }
774    }
775}
776
777macro_rules! float_bin_search {
778    ($typ:ident, $sample_typ:ident) => {
779        #[allow(missing_docs)]
780        pub mod $typ {
781            use super::float_samplers::$sample_typ;
782
783            use core::ops;
784            #[cfg(not(feature = "std"))]
785            use num_traits::float::FloatCore;
786
787            use rand::Rng;
788
789            use super::{FloatLayout, FloatTypes};
790            use crate::strategy::*;
791            use crate::test_runner::TestRunner;
792
793            float_any!($typ);
794
795            /// Shrinks a float towards 0, using binary search to find boundary
796            /// points.
797            ///
798            /// Non-finite values immediately shrink to 0.
799            #[derive(Clone, Copy, Debug)]
800            pub struct BinarySearch {
801                lo: $typ,
802                curr: $typ,
803                hi: $typ,
804                allowed: FloatTypes,
805            }
806
807            impl BinarySearch {
808                /// Creates a new binary searcher starting at the given value.
809                pub fn new(start: $typ) -> Self {
810                    BinarySearch {
811                        lo: 0.0,
812                        curr: start,
813                        hi: start,
814                        allowed: FloatTypes::all(),
815                    }
816                }
817
818                fn new_with_types(start: $typ, allowed: FloatTypes) -> Self {
819                    BinarySearch {
820                        lo: 0.0,
821                        curr: start,
822                        hi: start,
823                        allowed,
824                    }
825                }
826
827                /// Creates a new binary searcher which will not produce values
828                /// on the other side of `lo` or `hi` from `start`. `lo` is
829                /// inclusive, `hi` is exclusive.
830                fn new_clamped(lo: $typ, start: $typ, hi: $typ) -> Self {
831                    BinarySearch {
832                        lo: if start.is_sign_negative() {
833                            hi.min(0.0)
834                        } else {
835                            lo.max(0.0)
836                        },
837                        hi: start,
838                        curr: start,
839                        allowed: FloatTypes::all(),
840                    }
841                }
842
843                fn current_allowed(&self) -> bool {
844                    use core::num::FpCategory::*;
845
846                    // Don't reposition if the new value is not allowed
847                    let class_allowed = match self.curr.classify() {
848                        Nan =>
849                        // We don't need to inspect whether the
850                        // signallingness of the NaN matches the allowed
851                        // set, as we never try to switch between them,
852                        // instead shrinking to 0.
853                        {
854                            self.allowed.contains(FloatTypes::QUIET_NAN)
855                                || self
856                                    .allowed
857                                    .contains(FloatTypes::SIGNALING_NAN)
858                        }
859                        Infinite => self.allowed.contains(FloatTypes::INFINITE),
860                        Zero => self.allowed.contains(FloatTypes::ZERO),
861                        Subnormal => {
862                            self.allowed.contains(FloatTypes::SUBNORMAL)
863                        }
864                        Normal => self.allowed.contains(FloatTypes::NORMAL),
865                    };
866                    let signum = self.curr.signum();
867                    let sign_allowed = if signum > 0.0 {
868                        self.allowed.contains(FloatTypes::POSITIVE)
869                    } else if signum < 0.0 {
870                        self.allowed.contains(FloatTypes::NEGATIVE)
871                    } else {
872                        true
873                    };
874
875                    class_allowed && sign_allowed
876                }
877
878                fn ensure_acceptable(&mut self) {
879                    while !self.current_allowed() {
880                        if !self.complicate_once() {
881                            panic!(
882                                "Unable to complicate floating-point back \
883                                 to acceptable value"
884                            );
885                        }
886                    }
887                }
888
889                fn reposition(&mut self) -> bool {
890                    let interval = self.hi - self.lo;
891                    let interval =
892                        if interval.is_finite() { interval } else { 0.0 };
893                    let new_mid = self.lo + interval / 2.0;
894
895                    let new_mid = if new_mid == self.curr || 0.0 == interval {
896                        new_mid
897                    } else {
898                        self.lo
899                    };
900
901                    if new_mid == self.curr {
902                        false
903                    } else {
904                        self.curr = new_mid;
905                        true
906                    }
907                }
908
909                fn done(lo: $typ, hi: $typ) -> bool {
910                    (lo.abs() > hi.abs() && !hi.is_nan()) || lo.is_nan()
911                }
912
913                fn complicate_once(&mut self) -> bool {
914                    if BinarySearch::done(self.lo, self.hi) {
915                        return false;
916                    }
917
918                    self.lo = if self.curr == self.lo {
919                        self.hi
920                    } else {
921                        self.curr
922                    };
923
924                    self.reposition()
925                }
926            }
927            impl ValueTree for BinarySearch {
928                type Value = $typ;
929
930                fn current(&self) -> $typ {
931                    self.curr
932                }
933
934                fn simplify(&mut self) -> bool {
935                    if BinarySearch::done(self.lo, self.hi) {
936                        return false;
937                    }
938
939                    self.hi = self.curr;
940                    if self.reposition() {
941                        self.ensure_acceptable();
942                        true
943                    } else {
944                        false
945                    }
946                }
947
948                fn complicate(&mut self) -> bool {
949                    if self.complicate_once() {
950                        self.ensure_acceptable();
951                        true
952                    } else {
953                        false
954                    }
955                }
956            }
957
958            numeric_api!($typ, $sample_typ, 0.0);
959        }
960    };
961}
962
963#[cfg(feature = "f16")]
964float_bin_search!(f16, F16U);
965float_bin_search!(f32, F32U);
966float_bin_search!(f64, F64U);
967
968#[cfg(test)]
969mod test {
970    use crate::strategy::*;
971    use crate::test_runner::*;
972
973    use super::*;
974
975    #[test]
976    fn u8_inclusive_end_included() {
977        let mut runner = TestRunner::deterministic();
978        let mut ok = 0;
979        for _ in 0..20 {
980            let tree = (0..=1).new_tree(&mut runner).unwrap();
981            let test = runner.run_one(tree, |v| {
982                prop_assert_eq!(v, 1);
983                Ok(())
984            });
985            if test.is_ok() {
986                ok += 1;
987            }
988        }
989        assert!(ok > 1, "inclusive end not included.");
990    }
991
992    #[test]
993    fn u8_inclusive_to_end_included() {
994        let mut runner = TestRunner::deterministic();
995        let mut ok = 0;
996        for _ in 0..20 {
997            let tree = (..=1u8).new_tree(&mut runner).unwrap();
998            let test = runner.run_one(tree, |v| {
999                prop_assert_eq!(v, 1);
1000                Ok(())
1001            });
1002            if test.is_ok() {
1003                ok += 1;
1004            }
1005        }
1006        assert!(ok > 1, "inclusive end not included.");
1007    }
1008
1009    #[test]
1010    fn i8_binary_search_always_converges() {
1011        fn assert_converges<P: Fn(i32) -> bool>(start: i8, pass: P) {
1012            let mut state = i8::BinarySearch::new(start);
1013            loop {
1014                if !pass(state.current() as i32) {
1015                    if !state.simplify() {
1016                        break;
1017                    }
1018                } else {
1019                    if !state.complicate() {
1020                        break;
1021                    }
1022                }
1023            }
1024
1025            assert!(!pass(state.current() as i32));
1026            assert!(
1027                pass(state.current() as i32 - 1)
1028                    || pass(state.current() as i32 + 1)
1029            );
1030        }
1031
1032        for start in -128..0 {
1033            for target in start + 1..1 {
1034                assert_converges(start as i8, |v| v > target);
1035            }
1036        }
1037
1038        for start in 0..128 {
1039            for target in 0..start {
1040                assert_converges(start as i8, |v| v < target);
1041            }
1042        }
1043    }
1044
1045    #[test]
1046    fn u8_binary_search_always_converges() {
1047        fn assert_converges<P: Fn(u32) -> bool>(start: u8, pass: P) {
1048            let mut state = u8::BinarySearch::new(start);
1049            loop {
1050                if !pass(state.current() as u32) {
1051                    if !state.simplify() {
1052                        break;
1053                    }
1054                } else {
1055                    if !state.complicate() {
1056                        break;
1057                    }
1058                }
1059            }
1060
1061            assert!(!pass(state.current() as u32));
1062            assert!(pass(state.current() as u32 - 1));
1063        }
1064
1065        for start in 0..255 {
1066            for target in 0..start {
1067                assert_converges(start as u8, |v| v <= target);
1068            }
1069        }
1070    }
1071
1072    #[test]
1073    fn signed_integer_range_including_zero_converges_to_zero() {
1074        let mut runner = TestRunner::default();
1075        for _ in 0..100 {
1076            let mut state = (-42i32..64i32).new_tree(&mut runner).unwrap();
1077            let init_value = state.current();
1078            assert!(init_value >= -42 && init_value < 64);
1079
1080            while state.simplify() {
1081                let v = state.current();
1082                assert!(v >= -42 && v < 64);
1083            }
1084
1085            assert_eq!(0, state.current());
1086        }
1087    }
1088
1089    #[test]
1090    fn negative_integer_range_stays_in_bounds() {
1091        let mut runner = TestRunner::default();
1092        for _ in 0..100 {
1093            let mut state = (..-42i32).new_tree(&mut runner).unwrap();
1094            let init_value = state.current();
1095            assert!(init_value < -42);
1096
1097            while state.simplify() {
1098                assert!(
1099                    state.current() < -42,
1100                    "Violated bounds: {}",
1101                    state.current()
1102                );
1103            }
1104
1105            assert_eq!(-43, state.current());
1106        }
1107    }
1108
1109    #[test]
1110    fn positive_signed_integer_range_stays_in_bounds() {
1111        let mut runner = TestRunner::default();
1112        for _ in 0..100 {
1113            let mut state = (42i32..).new_tree(&mut runner).unwrap();
1114            let init_value = state.current();
1115            assert!(init_value >= 42);
1116
1117            while state.simplify() {
1118                assert!(
1119                    state.current() >= 42,
1120                    "Violated bounds: {}",
1121                    state.current()
1122                );
1123            }
1124
1125            assert_eq!(42, state.current());
1126        }
1127    }
1128
1129    #[test]
1130    fn unsigned_integer_range_stays_in_bounds() {
1131        let mut runner = TestRunner::default();
1132        for _ in 0..100 {
1133            let mut state = (42u32..56u32).new_tree(&mut runner).unwrap();
1134            let init_value = state.current();
1135            assert!(init_value >= 42 && init_value < 56);
1136
1137            while state.simplify() {
1138                assert!(
1139                    state.current() >= 42,
1140                    "Violated bounds: {}",
1141                    state.current()
1142                );
1143            }
1144
1145            assert_eq!(42, state.current());
1146        }
1147    }
1148
1149    mod contract_sanity {
1150        macro_rules! contract_sanity {
1151            ($t:tt) => {
1152                mod $t {
1153                    use crate::strategy::check_strategy_sanity;
1154
1155                    const FORTY_TWO: $t = 42 as $t;
1156                    const FIFTY_SIX: $t = 56 as $t;
1157
1158                    #[test]
1159                    fn range() {
1160                        check_strategy_sanity(FORTY_TWO..FIFTY_SIX, None);
1161                    }
1162
1163                    #[test]
1164                    fn range_inclusive() {
1165                        check_strategy_sanity(FORTY_TWO..=FIFTY_SIX, None);
1166                    }
1167
1168                    #[test]
1169                    fn range_to() {
1170                        check_strategy_sanity(..FIFTY_SIX, None);
1171                    }
1172
1173                    #[test]
1174                    fn range_to_inclusive() {
1175                        check_strategy_sanity(..=FIFTY_SIX, None);
1176                    }
1177
1178                    #[test]
1179                    fn range_from() {
1180                        check_strategy_sanity(FORTY_TWO.., None);
1181                    }
1182                }
1183            };
1184        }
1185        contract_sanity!(u8);
1186        contract_sanity!(i8);
1187        contract_sanity!(u16);
1188        contract_sanity!(i16);
1189        contract_sanity!(u32);
1190        contract_sanity!(i32);
1191        contract_sanity!(u64);
1192        contract_sanity!(i64);
1193        contract_sanity!(usize);
1194        contract_sanity!(isize);
1195        #[cfg(feature = "f16")]
1196        contract_sanity!(f16);
1197        contract_sanity!(f32);
1198        contract_sanity!(f64);
1199    }
1200
1201    #[test]
1202    fn unsigned_integer_binsearch_simplify_complicate_contract_upheld() {
1203        check_strategy_sanity(0u32..1000u32, None);
1204        check_strategy_sanity(0u32..1u32, None);
1205    }
1206
1207    #[test]
1208    fn signed_integer_binsearch_simplify_complicate_contract_upheld() {
1209        check_strategy_sanity(0i32..1000i32, None);
1210        check_strategy_sanity(0i32..1i32, None);
1211    }
1212
1213    #[test]
1214    fn positive_float_simplifies_to_zero() {
1215        let mut runner = TestRunner::default();
1216        let mut value = (0.0f64..2.0).new_tree(&mut runner).unwrap();
1217
1218        while value.simplify() {}
1219
1220        assert_eq!(0.0, value.current());
1221    }
1222
1223    #[test]
1224    fn positive_float_simplifies_to_base() {
1225        let mut runner = TestRunner::default();
1226        let mut value = (1.0f64..2.0).new_tree(&mut runner).unwrap();
1227
1228        while value.simplify() {}
1229
1230        assert_eq!(1.0, value.current());
1231    }
1232
1233    #[test]
1234    fn negative_float_simplifies_to_zero() {
1235        let mut runner = TestRunner::default();
1236        let mut value = (-2.0f64..0.0).new_tree(&mut runner).unwrap();
1237
1238        while value.simplify() {}
1239
1240        assert_eq!(0.0, value.current());
1241    }
1242
1243    #[test]
1244    fn positive_float_complicates_to_original() {
1245        let mut runner = TestRunner::default();
1246        let mut value = (1.0f64..2.0).new_tree(&mut runner).unwrap();
1247        let orig = value.current();
1248
1249        assert!(value.simplify());
1250        while value.complicate() {}
1251
1252        assert_eq!(orig, value.current());
1253    }
1254
1255    #[test]
1256    fn positive_infinity_simplifies_directly_to_zero() {
1257        let mut value = f64::BinarySearch::new(::std::f64::INFINITY);
1258
1259        assert!(value.simplify());
1260        assert_eq!(0.0, value.current());
1261        assert!(value.complicate());
1262        assert_eq!(::std::f64::INFINITY, value.current());
1263        assert!(!value.clone().complicate());
1264        assert!(!value.clone().simplify());
1265    }
1266
1267    #[test]
1268    fn negative_infinity_simplifies_directly_to_zero() {
1269        let mut value = f64::BinarySearch::new(::std::f64::NEG_INFINITY);
1270
1271        assert!(value.simplify());
1272        assert_eq!(0.0, value.current());
1273        assert!(value.complicate());
1274        assert_eq!(::std::f64::NEG_INFINITY, value.current());
1275        assert!(!value.clone().complicate());
1276        assert!(!value.clone().simplify());
1277    }
1278
1279    #[test]
1280    fn nan_simplifies_directly_to_zero() {
1281        let mut value = f64::BinarySearch::new(::std::f64::NAN);
1282
1283        assert!(value.simplify());
1284        assert_eq!(0.0, value.current());
1285        assert!(value.complicate());
1286        assert!(value.current().is_nan());
1287        assert!(!value.clone().complicate());
1288        assert!(!value.clone().simplify());
1289    }
1290
1291    #[test]
1292    fn float_simplifies_to_smallest_normal() {
1293        let mut runner = TestRunner::default();
1294        let mut value = (f64::MIN_POSITIVE..2.0)
1295            .new_tree(&mut runner)
1296            .unwrap();
1297
1298        while value.simplify() {}
1299
1300        assert_eq!(f64::MIN_POSITIVE, value.current());
1301    }
1302
1303    macro_rules! float_generation_test_body {
1304        ($strategy:ident, $typ:ident) => {
1305            use std::num::FpCategory;
1306
1307            let strategy = $strategy;
1308            let bits = strategy.normal_bits();
1309
1310            let mut seen_positive = 0;
1311            let mut seen_negative = 0;
1312            let mut seen_normal = 0;
1313            let mut seen_subnormal = 0;
1314            let mut seen_zero = 0;
1315            let mut seen_infinite = 0;
1316            let mut seen_quiet_nan = 0;
1317            let mut seen_signaling_nan = 0;
1318            let mut runner = TestRunner::deterministic();
1319
1320            // Check whether this version of Rust honours the NaN payload in
1321            // from_bits
1322            let fidelity_1 = f32::from_bits(0x7F80_0001).to_bits();
1323            let fidelity_2 = f32::from_bits(0xFF80_0001).to_bits();
1324            let nan_fidelity = fidelity_1 != fidelity_2;
1325
1326            for _ in 0..1024 {
1327                let mut tree = strategy.new_tree(&mut runner).unwrap();
1328                let mut increment = 1;
1329
1330                loop {
1331                    let value = tree.current();
1332
1333                    let sign = value.signum(); // So we correctly handle -0
1334                    if sign < 0.0 {
1335                        prop_assert!(bits.contains(FloatTypes::NEGATIVE));
1336                        seen_negative += increment;
1337                    } else if sign > 0.0 {
1338                        // i.e., not NaN
1339                        prop_assert!(bits.contains(FloatTypes::POSITIVE));
1340                        seen_positive += increment;
1341                    }
1342
1343                    match value.classify() {
1344                        FpCategory::Nan if nan_fidelity => {
1345                            let raw = value.to_bits();
1346                            let is_negative = raw << 1 >> 1 != raw;
1347                            if is_negative {
1348                                prop_assert!(
1349                                    bits.contains(FloatTypes::NEGATIVE)
1350                                );
1351                                seen_negative += increment;
1352                            } else {
1353                                prop_assert!(
1354                                    bits.contains(FloatTypes::POSITIVE)
1355                                );
1356                                seen_positive += increment;
1357                            }
1358
1359                            let is_quiet = raw & ($typ::EXP_MASK >> 1)
1360                                == $typ::NAN.to_bits() & ($typ::EXP_MASK >> 1);
1361                            if is_quiet {
1362                                // x86/AMD64 turn signalling NaNs into quiet
1363                                // NaNs quite aggressively depending on what
1364                                // registers LLVM decides to use to pass the
1365                                // value around, so accept either case here.
1366                                prop_assert!(
1367                                    bits.contains(FloatTypes::QUIET_NAN)
1368                                        || bits.contains(
1369                                            FloatTypes::SIGNALING_NAN
1370                                        )
1371                                );
1372                                seen_quiet_nan += increment;
1373                                seen_signaling_nan += increment;
1374                            } else {
1375                                prop_assert!(
1376                                    bits.contains(FloatTypes::SIGNALING_NAN)
1377                                );
1378                                seen_signaling_nan += increment;
1379                            }
1380                        }
1381
1382                        FpCategory::Nan => {
1383                            // Since safe Rust doesn't currently allow
1384                            // generating any NaN other than one particular
1385                            // payload, don't check the sign or signallingness
1386                            // and consider this to be both signs and
1387                            // signallingness for counting purposes.
1388                            seen_positive += increment;
1389                            seen_negative += increment;
1390                            seen_quiet_nan += increment;
1391                            seen_signaling_nan += increment;
1392                            prop_assert!(
1393                                bits.contains(FloatTypes::QUIET_NAN)
1394                                    || bits.contains(FloatTypes::SIGNALING_NAN)
1395                            );
1396                        }
1397                        FpCategory::Infinite => {
1398                            prop_assert!(bits.contains(FloatTypes::INFINITE));
1399                            seen_infinite += increment;
1400                        }
1401                        FpCategory::Zero => {
1402                            prop_assert!(bits.contains(FloatTypes::ZERO));
1403                            seen_zero += increment;
1404                        }
1405                        FpCategory::Subnormal => {
1406                            prop_assert!(bits.contains(FloatTypes::SUBNORMAL));
1407                            seen_subnormal += increment;
1408                        }
1409                        FpCategory::Normal => {
1410                            prop_assert!(bits.contains(FloatTypes::NORMAL));
1411                            seen_normal += increment;
1412                        }
1413                    }
1414
1415                    // Don't count simplified values towards the counts
1416                    increment = 0;
1417                    if !tree.simplify() {
1418                        break;
1419                    }
1420                }
1421            }
1422
1423            if bits.contains(FloatTypes::POSITIVE) {
1424                prop_assert!(seen_positive > 200);
1425            }
1426            if bits.contains(FloatTypes::NEGATIVE) {
1427                prop_assert!(seen_negative > 200);
1428            }
1429            if bits.contains(FloatTypes::NORMAL) {
1430                prop_assert!(seen_normal > 100);
1431            }
1432            if bits.contains(FloatTypes::SUBNORMAL) {
1433                prop_assert!(seen_subnormal > 5);
1434            }
1435            if bits.contains(FloatTypes::ZERO) {
1436                prop_assert!(seen_zero > 5);
1437            }
1438            if bits.contains(FloatTypes::INFINITE) {
1439                prop_assert!(seen_infinite > 0);
1440            }
1441            if bits.contains(FloatTypes::QUIET_NAN) {
1442                prop_assert!(seen_quiet_nan > 0);
1443            }
1444            if bits.contains(FloatTypes::SIGNALING_NAN) {
1445                prop_assert!(seen_signaling_nan > 0);
1446            }
1447        };
1448    }
1449
1450    proptest! {
1451        #![proptest_config(crate::test_runner::Config::with_cases(1024))]
1452
1453        #[cfg(feature = "f16")]
1454        #[test]
1455        fn f16_any_generates_desired_values(
1456            strategy in crate::bits::u32::ANY.prop_map(f16::Any::from_bits)
1457        ) {
1458            float_generation_test_body!(strategy, f16);
1459        }
1460
1461        #[cfg(feature = "f16")]
1462        #[test]
1463        fn f16_any_sanity(
1464            strategy in crate::bits::u32::ANY.prop_map(f16::Any::from_bits)
1465        ) {
1466            check_strategy_sanity(strategy, Some(CheckStrategySanityOptions {
1467                strict_complicate_after_simplify: false,
1468                .. CheckStrategySanityOptions::default()
1469            }));
1470        }
1471
1472        #[test]
1473        fn f32_any_generates_desired_values(
1474            strategy in crate::bits::u32::ANY.prop_map(f32::Any::from_bits)
1475        ) {
1476            float_generation_test_body!(strategy, f32);
1477        }
1478
1479        #[test]
1480        fn f32_any_sanity(
1481            strategy in crate::bits::u32::ANY.prop_map(f32::Any::from_bits)
1482        ) {
1483            check_strategy_sanity(strategy, Some(CheckStrategySanityOptions {
1484                strict_complicate_after_simplify: false,
1485                .. CheckStrategySanityOptions::default()
1486            }));
1487        }
1488
1489        #[test]
1490        fn f64_any_generates_desired_values(
1491            strategy in crate::bits::u32::ANY.prop_map(f64::Any::from_bits)
1492        ) {
1493            float_generation_test_body!(strategy, f64);
1494        }
1495
1496        #[test]
1497        fn f64_any_sanity(
1498            strategy in crate::bits::u32::ANY.prop_map(f64::Any::from_bits)
1499        ) {
1500            check_strategy_sanity(strategy, Some(CheckStrategySanityOptions {
1501                strict_complicate_after_simplify: false,
1502                .. CheckStrategySanityOptions::default()
1503            }));
1504        }
1505    }
1506
1507    mod panic_on_empty {
1508        macro_rules! panic_on_empty {
1509            ($t:tt) => {
1510                mod $t {
1511                    use crate::strategy::Strategy;
1512                    use crate::test_runner::TestRunner;
1513                    use std::panic;
1514                    use std::string::String;
1515
1516                    const ZERO: $t = 0 as $t;
1517                    const ONE: $t = 1 as $t;
1518
1519                    #[test]
1520                    fn range() {
1521                        assert_eq!(
1522                            panic::catch_unwind(|| {
1523                                let mut runner = TestRunner::deterministic();
1524                                let _ = (ZERO..ZERO).new_tree(&mut runner);
1525                            })
1526                            .err()
1527                            .and_then(|a| a
1528                                .downcast_ref::<String>()
1529                                .map(|s| {
1530                                    s == "Invalid use of empty range 0..0."
1531                                })),
1532                            Some(true)
1533                        );
1534                    }
1535
1536                    #[test]
1537                    fn range_inclusive() {
1538                        assert_eq!(
1539                            panic::catch_unwind(|| {
1540                                let mut runner = TestRunner::deterministic();
1541                                let _ = (ONE..=ZERO).new_tree(&mut runner);
1542                            })
1543                            .err()
1544                            .and_then(|a| a
1545                                .downcast_ref::<String>()
1546                                .map(|s| {
1547                                    s == "Invalid use of empty range 1..=0."
1548                                })),
1549                            Some(true)
1550                        );
1551                    }
1552                }
1553            };
1554        }
1555        panic_on_empty!(u8);
1556        panic_on_empty!(i8);
1557        panic_on_empty!(u16);
1558        panic_on_empty!(i16);
1559        panic_on_empty!(u32);
1560        panic_on_empty!(i32);
1561        panic_on_empty!(u64);
1562        panic_on_empty!(i64);
1563        panic_on_empty!(usize);
1564        panic_on_empty!(isize);
1565        #[cfg(feature = "f16")]
1566        panic_on_empty!(f16);
1567        panic_on_empty!(f32);
1568        panic_on_empty!(f64);
1569    }
1570}