]> git.proxmox.com Git - rustc.git/blame - library/core/tests/num/flt2dec/random.rs
New upstream version 1.48.0~beta.8+dfsg1
[rustc.git] / library / core / tests / num / flt2dec / random.rs
CommitLineData
0531ce1d 1#![cfg(not(target_arch = "wasm32"))]
abe05a73 2
1b1a35ee 3use std::mem::MaybeUninit;
abe05a73
XL
4use std::str;
5
abe05a73
XL
6use core::num::flt2dec::strategy::grisu::format_exact_opt;
7use core::num::flt2dec::strategy::grisu::format_shortest_opt;
60c5eb7d
XL
8use core::num::flt2dec::MAX_SIG_DIGITS;
9use core::num::flt2dec::{decode, DecodableFloat, Decoded, FullDecoded};
abe05a73 10
b7449926 11use rand::distributions::{Distribution, Uniform};
60c5eb7d
XL
12use rand::rngs::StdRng;
13use rand::SeedableRng;
0531ce1d 14
abe05a73
XL
15pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
16 match decode(v).1 {
17 FullDecoded::Finite(decoded) => decoded,
60c5eb7d 18 full_decoded => panic!("expected finite, got {:?} instead", full_decoded),
abe05a73
XL
19 }
20}
21
abe05a73 22fn iterate<F, G, V>(func: &str, k: usize, n: usize, mut f: F, mut g: G, mut v: V) -> (usize, usize)
60c5eb7d 23where
1b1a35ee
XL
24 F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> Option<(&'a [u8], i16)>,
25 G: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> (&'a [u8], i16),
60c5eb7d
XL
26 V: FnMut(usize) -> Decoded,
27{
abe05a73
XL
28 assert!(k <= 1024);
29
30 let mut npassed = 0; // f(x) = Some(g(x))
31 let mut nignored = 0; // f(x) = None
32
33 for i in 0..n {
34 if (i & 0xfffff) == 0 {
60c5eb7d
XL
35 println!(
36 "in progress, {:x}/{:x} (ignored={} passed={} failed={})",
37 i,
38 n,
39 nignored,
40 npassed,
41 i - nignored - npassed
42 );
abe05a73
XL
43 }
44
45 let decoded = v(i);
1b1a35ee
XL
46 let mut buf1 = [MaybeUninit::new(0); 1024];
47 if let Some((buf1, e1)) = f(&decoded, &mut buf1[..k]) {
48 let mut buf2 = [MaybeUninit::new(0); 1024];
49 let (buf2, e2) = g(&decoded, &mut buf2[..k]);
50 if e1 == e2 && buf1 == buf2 {
abe05a73
XL
51 npassed += 1;
52 } else {
60c5eb7d
XL
53 println!(
54 "equivalence test failed, {:x}/{:x}: {:?} f(i)={}e{} g(i)={}e{}",
55 i,
56 n,
57 decoded,
1b1a35ee 58 str::from_utf8(buf1).unwrap(),
60c5eb7d 59 e1,
1b1a35ee 60 str::from_utf8(buf2).unwrap(),
60c5eb7d
XL
61 e2
62 );
abe05a73
XL
63 }
64 } else {
65 nignored += 1;
66 }
67 }
60c5eb7d
XL
68 println!(
69 "{}({}): done, ignored={} passed={} failed={}",
70 func,
71 k,
72 nignored,
73 npassed,
74 n - nignored - npassed
75 );
76 assert!(
77 nignored + npassed == n,
78 "{}({}): {} out of {} values returns an incorrect value!",
79 func,
80 k,
81 n - nignored - npassed,
82 n
83 );
abe05a73
XL
84 (npassed, nignored)
85}
86
87pub fn f32_random_equivalence_test<F, G>(f: F, g: G, k: usize, n: usize)
60c5eb7d 88where
1b1a35ee
XL
89 F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> Option<(&'a [u8], i16)>,
90 G: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> (&'a [u8], i16),
60c5eb7d 91{
0731742a 92 if cfg!(target_os = "emscripten") {
60c5eb7d 93 return; // using rng pulls in i128 support, which doesn't work
0731742a 94 }
416331ca 95 let mut rng = StdRng::from_entropy();
b7449926 96 let f32_range = Uniform::new(0x0000_0001u32, 0x7f80_0000);
abe05a73 97 iterate("f32_random_equivalence_test", k, n, f, g, |_| {
b7449926 98 let x = f32::from_bits(f32_range.sample(&mut rng));
abe05a73
XL
99 decode_finite(x)
100 });
101}
102
103pub fn f64_random_equivalence_test<F, G>(f: F, g: G, k: usize, n: usize)
60c5eb7d 104where
1b1a35ee
XL
105 F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> Option<(&'a [u8], i16)>,
106 G: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> (&'a [u8], i16),
60c5eb7d 107{
0731742a 108 if cfg!(target_os = "emscripten") {
60c5eb7d 109 return; // using rng pulls in i128 support, which doesn't work
0731742a 110 }
416331ca 111 let mut rng = StdRng::from_entropy();
b7449926 112 let f64_range = Uniform::new(0x0000_0000_0000_0001u64, 0x7ff0_0000_0000_0000);
abe05a73 113 iterate("f64_random_equivalence_test", k, n, f, g, |_| {
b7449926 114 let x = f64::from_bits(f64_range.sample(&mut rng));
abe05a73
XL
115 decode_finite(x)
116 });
117}
118
119pub fn f32_exhaustive_equivalence_test<F, G>(f: F, g: G, k: usize)
60c5eb7d 120where
1b1a35ee
XL
121 F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> Option<(&'a [u8], i16)>,
122 G: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> (&'a [u8], i16),
60c5eb7d 123{
abe05a73
XL
124 // we have only 2^23 * (2^8 - 1) - 1 = 2,139,095,039 positive finite f32 values,
125 // so why not simply testing all of them?
126 //
127 // this is of course very stressful (and thus should be behind an `#[ignore]` attribute),
128 // but with `-C opt-level=3 -C lto` this only takes about an hour or so.
129
0731742a 130 // iterate from 0x0000_0001 to 0x7f7f_ffff, i.e., all finite ranges
60c5eb7d
XL
131 let (npassed, nignored) =
132 iterate("f32_exhaustive_equivalence_test", k, 0x7f7f_ffff, f, g, |i: usize| {
133 let x = f32::from_bits(i as u32 + 1);
134 decode_finite(x)
135 });
abe05a73
XL
136 assert_eq!((npassed, nignored), (2121451881, 17643158));
137}
138
139#[test]
140fn shortest_random_equivalence_test() {
141 use core::num::flt2dec::strategy::dragon::format_shortest as fallback;
f9f354fc
XL
142 // Miri is too slow
143 let n = if cfg!(miri) { 10 } else { 10_000 };
416331ca 144
f9f354fc
XL
145 f64_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, n);
146 f32_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, n);
abe05a73
XL
147}
148
60c5eb7d
XL
149#[test]
150#[ignore] // it is too expensive
abe05a73
XL
151fn shortest_f32_exhaustive_equivalence_test() {
152 // it is hard to directly test the optimality of the output, but we can at least test if
153 // two different algorithms agree to each other.
154 //
155 // this reports the progress and the number of f32 values returned `None`.
156 // with `--nocapture` (and plenty of time and appropriate rustc flags), this should print:
157 // `done, ignored=17643158 passed=2121451881 failed=0`.
158
159 use core::num::flt2dec::strategy::dragon::format_shortest as fallback;
160 f32_exhaustive_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS);
161}
162
60c5eb7d
XL
163#[test]
164#[ignore] // it is too expensive
abe05a73
XL
165fn shortest_f64_hard_random_equivalence_test() {
166 // this again probably has to use appropriate rustc flags.
167
168 use core::num::flt2dec::strategy::dragon::format_shortest as fallback;
60c5eb7d 169 f64_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, 100_000_000);
abe05a73
XL
170}
171
172#[test]
173fn exact_f32_random_equivalence_test() {
174 use core::num::flt2dec::strategy::dragon::format_exact as fallback;
f9f354fc
XL
175 // Miri is too slow
176 let n = if cfg!(miri) { 3 } else { 1_000 };
416331ca 177
abe05a73 178 for k in 1..21 {
60c5eb7d
XL
179 f32_random_equivalence_test(
180 |d, buf| format_exact_opt(d, buf, i16::MIN),
181 |d, buf| fallback(d, buf, i16::MIN),
182 k,
f9f354fc 183 n,
60c5eb7d 184 );
abe05a73
XL
185 }
186}
187
188#[test]
189fn exact_f64_random_equivalence_test() {
190 use core::num::flt2dec::strategy::dragon::format_exact as fallback;
f9f354fc 191 // Miri is too slow
3dfed10e 192 let n = if cfg!(miri) { 2 } else { 1_000 };
416331ca 193
abe05a73 194 for k in 1..21 {
60c5eb7d
XL
195 f64_random_equivalence_test(
196 |d, buf| format_exact_opt(d, buf, i16::MIN),
197 |d, buf| fallback(d, buf, i16::MIN),
198 k,
f9f354fc 199 n,
60c5eb7d 200 );
abe05a73
XL
201 }
202}