]> git.lizzy.rs Git - rust.git/blob - src/libcore/tests/num/flt2dec/random.rs
Various minor/cosmetic improvements to code
[rust.git] / src / libcore / tests / num / flt2dec / random.rs
1 // Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 #![cfg(not(target_arch = "wasm32"))]
12
13 use std::i16;
14 use std::str;
15
16 use core::num::flt2dec::MAX_SIG_DIGITS;
17 use core::num::flt2dec::strategy::grisu::format_exact_opt;
18 use core::num::flt2dec::strategy::grisu::format_shortest_opt;
19 use core::num::flt2dec::{decode, DecodableFloat, FullDecoded, Decoded};
20
21 use rand::{FromEntropy, XorShiftRng};
22 use rand::distributions::{Distribution, Uniform};
23
24 pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
25     match decode(v).1 {
26         FullDecoded::Finite(decoded) => decoded,
27         full_decoded => panic!("expected finite, got {:?} instead", full_decoded)
28     }
29 }
30
31
32 fn iterate<F, G, V>(func: &str, k: usize, n: usize, mut f: F, mut g: G, mut v: V) -> (usize, usize)
33         where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>,
34               G: FnMut(&Decoded, &mut [u8]) -> (usize, i16),
35               V: FnMut(usize) -> Decoded {
36     assert!(k <= 1024);
37
38     let mut npassed = 0; // f(x) = Some(g(x))
39     let mut nignored = 0; // f(x) = None
40
41     for i in 0..n {
42         if (i & 0xfffff) == 0 {
43             println!("in progress, {:x}/{:x} (ignored={} passed={} failed={})",
44                      i, n, nignored, npassed, i - nignored - npassed);
45         }
46
47         let decoded = v(i);
48         let mut buf1 = [0; 1024];
49         if let Some((len1, e1)) = f(&decoded, &mut buf1[..k]) {
50             let mut buf2 = [0; 1024];
51             let (len2, e2) = g(&decoded, &mut buf2[..k]);
52             if e1 == e2 && &buf1[..len1] == &buf2[..len2] {
53                 npassed += 1;
54             } else {
55                 println!("equivalence test failed, {:x}/{:x}: {:?} f(i)={}e{} g(i)={}e{}",
56                          i, n, decoded, str::from_utf8(&buf1[..len1]).unwrap(), e1,
57                                         str::from_utf8(&buf2[..len2]).unwrap(), e2);
58             }
59         } else {
60             nignored += 1;
61         }
62     }
63     println!("{}({}): done, ignored={} passed={} failed={}",
64              func, k, nignored, npassed, n - nignored - npassed);
65     assert!(nignored + npassed == n,
66             "{}({}): {} out of {} values returns an incorrect value!",
67             func, k, n - nignored - npassed, n);
68     (npassed, nignored)
69 }
70
71 pub fn f32_random_equivalence_test<F, G>(f: F, g: G, k: usize, n: usize)
72         where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>,
73               G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) {
74     let mut rng = XorShiftRng::from_entropy();
75     let f32_range = Uniform::new(0x0000_0001u32, 0x7f80_0000);
76     iterate("f32_random_equivalence_test", k, n, f, g, |_| {
77         let x = f32::from_bits(f32_range.sample(&mut rng));
78         decode_finite(x)
79     });
80 }
81
82 pub fn f64_random_equivalence_test<F, G>(f: F, g: G, k: usize, n: usize)
83         where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>,
84               G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) {
85     let mut rng = XorShiftRng::from_entropy();
86     let f64_range = Uniform::new(0x0000_0000_0000_0001u64, 0x7ff0_0000_0000_0000);
87     iterate("f64_random_equivalence_test", k, n, f, g, |_| {
88         let x = f64::from_bits(f64_range.sample(&mut rng));
89         decode_finite(x)
90     });
91 }
92
93 pub fn f32_exhaustive_equivalence_test<F, G>(f: F, g: G, k: usize)
94         where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>,
95               G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) {
96     // we have only 2^23 * (2^8 - 1) - 1 = 2,139,095,039 positive finite f32 values,
97     // so why not simply testing all of them?
98     //
99     // this is of course very stressful (and thus should be behind an `#[ignore]` attribute),
100     // but with `-C opt-level=3 -C lto` this only takes about an hour or so.
101
102     // iterate from 0x0000_0001 to 0x7f7f_ffff, i.e., all finite ranges
103     let (npassed, nignored) = iterate("f32_exhaustive_equivalence_test",
104                                       k, 0x7f7f_ffff, f, g, |i: usize| {
105
106         let x = f32::from_bits(i as u32 + 1);
107         decode_finite(x)
108     });
109     assert_eq!((npassed, nignored), (2121451881, 17643158));
110 }
111
112 #[test]
113 fn shortest_random_equivalence_test() {
114     use core::num::flt2dec::strategy::dragon::format_shortest as fallback;
115     f64_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, 10_000);
116     f32_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, 10_000);
117 }
118
119 #[test] #[ignore] // it is too expensive
120 fn shortest_f32_exhaustive_equivalence_test() {
121     // it is hard to directly test the optimality of the output, but we can at least test if
122     // two different algorithms agree to each other.
123     //
124     // this reports the progress and the number of f32 values returned `None`.
125     // with `--nocapture` (and plenty of time and appropriate rustc flags), this should print:
126     // `done, ignored=17643158 passed=2121451881 failed=0`.
127
128     use core::num::flt2dec::strategy::dragon::format_shortest as fallback;
129     f32_exhaustive_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS);
130 }
131
132 #[test] #[ignore] // it is too expensive
133 fn shortest_f64_hard_random_equivalence_test() {
134     // this again probably has to use appropriate rustc flags.
135
136     use core::num::flt2dec::strategy::dragon::format_shortest as fallback;
137     f64_random_equivalence_test(format_shortest_opt, fallback,
138                                          MAX_SIG_DIGITS, 100_000_000);
139 }
140
141 #[test]
142 fn exact_f32_random_equivalence_test() {
143     use core::num::flt2dec::strategy::dragon::format_exact as fallback;
144     for k in 1..21 {
145         f32_random_equivalence_test(|d, buf| format_exact_opt(d, buf, i16::MIN),
146                                              |d, buf| fallback(d, buf, i16::MIN), k, 1_000);
147     }
148 }
149
150 #[test]
151 fn exact_f64_random_equivalence_test() {
152     use core::num::flt2dec::strategy::dragon::format_exact as fallback;
153     for k in 1..21 {
154         f64_random_equivalence_test(|d, buf| format_exact_opt(d, buf, i16::MIN),
155                                              |d, buf| fallback(d, buf, i16::MIN), k, 1_000);
156     }
157 }
158