]>
Commit | Line | Data |
---|---|---|
1b1a35ee | 1 | use std::mem::MaybeUninit; |
ba9703b0 | 2 | use std::{fmt, str}; |
d9579d0f | 3 | |
dfeec247 | 4 | use core::num::flt2dec::{decode, DecodableFloat, Decoded, FullDecoded}; |
136023e0 | 5 | use core::num::flt2dec::{round_up, Sign, MAX_SIG_DIGITS}; |
dfeec247 XL |
6 | use core::num::flt2dec::{ |
7 | to_exact_exp_str, to_exact_fixed_str, to_shortest_exp_str, to_shortest_str, | |
8 | }; | |
136023e0 | 9 | use core::num::fmt::{Formatted, Part}; |
d9579d0f AL |
10 | |
11 | pub use test::Bencher; | |
12 | ||
13 | mod estimator; | |
d9579d0f AL |
14 | mod strategy { |
15 | mod dragon; | |
16 | mod grisu; | |
17 | } | |
0531ce1d | 18 | mod random; |
d9579d0f AL |
19 | |
20 | pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded { | |
21 | match decode(v).1 { | |
22 | FullDecoded::Finite(decoded) => decoded, | |
ee023bcb | 23 | full_decoded => panic!("expected finite, got {full_decoded:?} instead"), |
d9579d0f AL |
24 | } |
25 | } | |
26 | ||
27 | macro_rules! check_shortest { | |
28 | ($f:ident($v:expr) => $buf:expr, $exp:expr) => ( | |
29 | check_shortest!($f($v) => $buf, $exp; | |
30 | "shortest mismatch for v={v}: actual {actual:?}, expected {expected:?}", | |
31 | v = stringify!($v)) | |
32 | ); | |
33 | ||
34 | ($f:ident{$($k:ident: $v:expr),+} => $buf:expr, $exp:expr) => ( | |
35 | check_shortest!($f{$($k: $v),+} => $buf, $exp; | |
36 | "shortest mismatch for {v:?}: actual {actual:?}, expected {expected:?}", | |
37 | v = Decoded { $($k: $v),+ }) | |
38 | ); | |
39 | ||
40 | ($f:ident($v:expr) => $buf:expr, $exp:expr; $fmt:expr, $($key:ident = $val:expr),*) => ({ | |
1b1a35ee XL |
41 | let mut buf = [MaybeUninit::new(b'_'); MAX_SIG_DIGITS]; |
42 | let (buf, k) = $f(&decode_finite($v), &mut buf); | |
43 | assert!((buf, k) == ($buf, $exp), | |
44 | $fmt, actual = (str::from_utf8(buf).unwrap(), k), | |
d9579d0f AL |
45 | expected = (str::from_utf8($buf).unwrap(), $exp), |
46 | $($key = $val),*); | |
47 | }); | |
48 | ||
49 | ($f:ident{$($k:ident: $v:expr),+} => $buf:expr, $exp:expr; | |
50 | $fmt:expr, $($key:ident = $val:expr),*) => ({ | |
1b1a35ee XL |
51 | let mut buf = [MaybeUninit::new(b'_'); MAX_SIG_DIGITS]; |
52 | let (buf, k) = $f(&Decoded { $($k: $v),+ }, &mut buf); | |
53 | assert!((buf, k) == ($buf, $exp), | |
54 | $fmt, actual = (str::from_utf8(buf).unwrap(), k), | |
d9579d0f AL |
55 | expected = (str::from_utf8($buf).unwrap(), $exp), |
56 | $($key = $val),*); | |
57 | }) | |
58 | } | |
59 | ||
60 | macro_rules! try_exact { | |
61 | ($f:ident($decoded:expr) => $buf:expr, $expected:expr, $expectedk:expr; | |
62 | $fmt:expr, $($key:ident = $val:expr),*) => ({ | |
1b1a35ee XL |
63 | let (buf, k) = $f($decoded, &mut $buf[..$expected.len()], i16::MIN); |
64 | assert!((buf, k) == ($expected, $expectedk), | |
65 | $fmt, actual = (str::from_utf8(buf).unwrap(), k), | |
d9579d0f AL |
66 | expected = (str::from_utf8($expected).unwrap(), $expectedk), |
67 | $($key = $val),*); | |
68 | }) | |
69 | } | |
70 | ||
71 | macro_rules! try_fixed { | |
72 | ($f:ident($decoded:expr) => $buf:expr, $request:expr, $expected:expr, $expectedk:expr; | |
73 | $fmt:expr, $($key:ident = $val:expr),*) => ({ | |
1b1a35ee XL |
74 | let (buf, k) = $f($decoded, &mut $buf[..], $request); |
75 | assert!((buf, k) == ($expected, $expectedk), | |
76 | $fmt, actual = (str::from_utf8(buf).unwrap(), k), | |
d9579d0f AL |
77 | expected = (str::from_utf8($expected).unwrap(), $expectedk), |
78 | $($key = $val),*); | |
79 | }) | |
80 | } | |
81 | ||
3157f602 XL |
82 | fn ldexp_f32(a: f32, b: i32) -> f32 { |
83 | ldexp_f64(a as f64, b) as f32 | |
84 | } | |
85 | ||
86 | fn ldexp_f64(a: f64, b: i32) -> f64 { | |
dfeec247 | 87 | extern "C" { |
3157f602 XL |
88 | fn ldexp(x: f64, n: i32) -> f64; |
89 | } | |
60c5eb7d XL |
90 | // SAFETY: assuming a correct `ldexp` has been supplied, the given arguments cannot possibly |
91 | // cause undefined behavior | |
3157f602 XL |
92 | unsafe { ldexp(a, b) } |
93 | } | |
94 | ||
d9579d0f | 95 | fn check_exact<F, T>(mut f: F, v: T, vstr: &str, expected: &[u8], expectedk: i16) |
dfeec247 XL |
96 | where |
97 | T: DecodableFloat, | |
1b1a35ee | 98 | F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>], i16) -> (&'a [u8], i16), |
dfeec247 | 99 | { |
d9579d0f | 100 | // use a large enough buffer |
1b1a35ee | 101 | let mut buf = [MaybeUninit::new(b'_'); 1024]; |
d9579d0f AL |
102 | let mut expected_ = [b'_'; 1024]; |
103 | ||
104 | let decoded = decode_finite(v); | |
105 | let cut = expected.iter().position(|&c| c == b' '); | |
106 | ||
107 | // check significant digits | |
108 | for i in 1..cut.unwrap_or(expected.len() - 1) { | |
7453a54e | 109 | expected_[..i].copy_from_slice(&expected[..i]); |
d9579d0f AL |
110 | let mut expectedk_ = expectedk; |
111 | if expected[i] >= b'5' { | |
112 | // check if this is a rounding-to-even case. | |
113 | // we avoid rounding ...x5000... (with infinite zeroes) to ...(x+1) when x is even. | |
dfeec247 XL |
114 | if !(i + 1 < expected.len() |
115 | && expected[i - 1] & 1 == 0 | |
116 | && expected[i] == b'5' | |
117 | && expected[i + 1] == b' ') | |
118 | { | |
d9579d0f AL |
119 | // if this returns true, expected_[..i] is all `9`s and being rounded up. |
120 | // we should always return `100..00` (`i` digits) instead, since that's | |
121 | // what we can came up with `i` digits anyway. `round_up` assumes that | |
122 | // the adjustment to the length is done by caller, which we simply ignore. | |
1b1a35ee | 123 | if let Some(_) = round_up(&mut expected_[..i]) { |
dfeec247 XL |
124 | expectedk_ += 1; |
125 | } | |
d9579d0f AL |
126 | } |
127 | } | |
128 | ||
129 | try_exact!(f(&decoded) => &mut buf, &expected_[..i], expectedk_; | |
130 | "exact sigdigit mismatch for v={v}, i={i}: \ | |
131 | actual {actual:?}, expected {expected:?}", | |
132 | v = vstr, i = i); | |
133 | try_fixed!(f(&decoded) => &mut buf, expectedk_ - i as i16, &expected_[..i], expectedk_; | |
134 | "fixed sigdigit mismatch for v={v}, i={i}: \ | |
135 | actual {actual:?}, expected {expected:?}", | |
136 | v = vstr, i = i); | |
137 | } | |
138 | ||
139 | // check exact rounding for zero- and negative-width cases | |
140 | let start; | |
141 | if expected[0] >= b'5' { | |
142 | try_fixed!(f(&decoded) => &mut buf, expectedk, b"1", expectedk + 1; | |
143 | "zero-width rounding-up mismatch for v={v}: \ | |
144 | actual {actual:?}, expected {expected:?}", | |
145 | v = vstr); | |
146 | start = 1; | |
147 | } else { | |
148 | start = 0; | |
149 | } | |
150 | for i in start..-10 { | |
151 | try_fixed!(f(&decoded) => &mut buf, expectedk - i, b"", expectedk; | |
152 | "rounding-down mismatch for v={v}, i={i}: \ | |
153 | actual {actual:?}, expected {expected:?}", | |
154 | v = vstr, i = -i); | |
155 | } | |
156 | ||
157 | // check infinite zero digits | |
158 | if let Some(cut) = cut { | |
dfeec247 | 159 | for i in cut..expected.len() - 1 { |
7453a54e | 160 | expected_[..cut].copy_from_slice(&expected[..cut]); |
dfeec247 XL |
161 | for c in &mut expected_[cut..i] { |
162 | *c = b'0'; | |
163 | } | |
d9579d0f AL |
164 | |
165 | try_exact!(f(&decoded) => &mut buf, &expected_[..i], expectedk; | |
166 | "exact infzero mismatch for v={v}, i={i}: \ | |
167 | actual {actual:?}, expected {expected:?}", | |
168 | v = vstr, i = i); | |
169 | try_fixed!(f(&decoded) => &mut buf, expectedk - i as i16, &expected_[..i], expectedk; | |
170 | "fixed infzero mismatch for v={v}, i={i}: \ | |
171 | actual {actual:?}, expected {expected:?}", | |
172 | v = vstr, i = i); | |
173 | } | |
174 | } | |
175 | } | |
176 | ||
dfeec247 | 177 | trait TestableFloat: DecodableFloat + fmt::Display { |
e9174d1e SL |
178 | /// Returns `x * 2^exp`. Almost same to `std::{f32,f64}::ldexp`. |
179 | /// This is used for testing. | |
180 | fn ldexpi(f: i64, exp: isize) -> Self; | |
181 | } | |
182 | ||
183 | impl TestableFloat for f32 { | |
dfeec247 XL |
184 | fn ldexpi(f: i64, exp: isize) -> Self { |
185 | f as Self * (exp as Self).exp2() | |
186 | } | |
e9174d1e SL |
187 | } |
188 | ||
189 | impl TestableFloat for f64 { | |
dfeec247 XL |
190 | fn ldexpi(f: i64, exp: isize) -> Self { |
191 | f as Self * (exp as Self).exp2() | |
192 | } | |
e9174d1e SL |
193 | } |
194 | ||
d9579d0f | 195 | fn check_exact_one<F, T>(mut f: F, x: i64, e: isize, tstr: &str, expected: &[u8], expectedk: i16) |
dfeec247 XL |
196 | where |
197 | T: TestableFloat, | |
1b1a35ee | 198 | F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>], i16) -> (&'a [u8], i16), |
dfeec247 | 199 | { |
d9579d0f | 200 | // use a large enough buffer |
1b1a35ee | 201 | let mut buf = [MaybeUninit::new(b'_'); 1024]; |
e9174d1e | 202 | let v: T = TestableFloat::ldexpi(x, e); |
d9579d0f AL |
203 | let decoded = decode_finite(v); |
204 | ||
205 | try_exact!(f(&decoded) => &mut buf, &expected, expectedk; | |
206 | "exact mismatch for v={x}p{e}{t}: actual {actual:?}, expected {expected:?}", | |
207 | x = x, e = e, t = tstr); | |
208 | try_fixed!(f(&decoded) => &mut buf, expectedk - expected.len() as i16, &expected, expectedk; | |
209 | "fixed mismatch for v={x}p{e}{t}: actual {actual:?}, expected {expected:?}", | |
210 | x = x, e = e, t = tstr); | |
211 | } | |
212 | ||
213 | macro_rules! check_exact { | |
dfeec247 XL |
214 | ($f:ident($v:expr) => $buf:expr, $exp:expr) => { |
215 | check_exact(|d, b, k| $f(d, b, k), $v, stringify!($v), $buf, $exp) | |
216 | }; | |
d9579d0f AL |
217 | } |
218 | ||
219 | macro_rules! check_exact_one { | |
dfeec247 XL |
220 | ($f:ident($x:expr, $e:expr; $t:ty) => $buf:expr, $exp:expr) => { |
221 | check_exact_one::<_, $t>(|d, b, k| $f(d, b, k), $x, $e, stringify!($t), $buf, $exp) | |
222 | }; | |
d9579d0f AL |
223 | } |
224 | ||
225 | // in the following comments, three numbers are spaced by 1 ulp apart, | |
226 | // and the second one is being formatted. | |
227 | // | |
228 | // some tests are derived from [1]. | |
229 | // | |
230 | // [1] Vern Paxson, A Program for Testing IEEE Decimal-Binary Conversion | |
231 | // ftp://ftp.ee.lbl.gov/testbase-report.ps.Z | |
232 | ||
dfeec247 XL |
233 | pub fn f32_shortest_sanity_test<F>(mut f: F) |
234 | where | |
1b1a35ee | 235 | F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> (&'a [u8], i16), |
dfeec247 | 236 | { |
d9579d0f AL |
237 | // 0.0999999940395355224609375 |
238 | // 0.100000001490116119384765625 | |
239 | // 0.10000000894069671630859375 | |
240 | check_shortest!(f(0.1f32) => b"1", 0); | |
241 | ||
242 | // 0.333333313465118408203125 | |
243 | // 0.3333333432674407958984375 (1/3 in the default rounding) | |
244 | // 0.33333337306976318359375 | |
245 | check_shortest!(f(1.0f32/3.0) => b"33333334", 0); | |
246 | ||
247 | // 10^1 * 0.31415917873382568359375 | |
248 | // 10^1 * 0.31415920257568359375 | |
249 | // 10^1 * 0.31415922641754150390625 | |
250 | check_shortest!(f(3.141592f32) => b"3141592", 1); | |
251 | ||
252 | // 10^18 * 0.31415916243714048 | |
253 | // 10^18 * 0.314159196796878848 | |
254 | // 10^18 * 0.314159231156617216 | |
255 | check_shortest!(f(3.141592e17f32) => b"3141592", 18); | |
256 | ||
257 | // regression test for decoders | |
258 | // 10^8 * 0.3355443 | |
259 | // 10^8 * 0.33554432 | |
260 | // 10^8 * 0.33554436 | |
3157f602 | 261 | check_shortest!(f(ldexp_f32(1.0, 25)) => b"33554432", 8); |
d9579d0f AL |
262 | |
263 | // 10^39 * 0.340282326356119256160033759537265639424 | |
264 | // 10^39 * 0.34028234663852885981170418348451692544 | |
265 | // 10^39 * 0.340282366920938463463374607431768211456 | |
266 | check_shortest!(f(f32::MAX) => b"34028235", 39); | |
267 | ||
268 | // 10^-37 * 0.1175494210692441075487029444849287348827... | |
269 | // 10^-37 * 0.1175494350822287507968736537222245677818... | |
270 | // 10^-37 * 0.1175494490952133940450443629595204006810... | |
271 | check_shortest!(f(f32::MIN_POSITIVE) => b"11754944", -37); | |
272 | ||
273 | // 10^-44 * 0 | |
274 | // 10^-44 * 0.1401298464324817070923729583289916131280... | |
275 | // 10^-44 * 0.2802596928649634141847459166579832262560... | |
3157f602 | 276 | let minf32 = ldexp_f32(1.0, -149); |
d9579d0f AL |
277 | check_shortest!(f(minf32) => b"1", -44); |
278 | } | |
279 | ||
280 | pub fn f32_exact_sanity_test<F>(mut f: F) | |
dfeec247 | 281 | where |
1b1a35ee | 282 | F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>], i16) -> (&'a [u8], i16), |
dfeec247 | 283 | { |
3157f602 | 284 | let minf32 = ldexp_f32(1.0, -149); |
d9579d0f AL |
285 | |
286 | check_exact!(f(0.1f32) => b"100000001490116119384765625 ", 0); | |
287 | check_exact!(f(0.5f32) => b"5 ", 0); | |
288 | check_exact!(f(1.0f32/3.0) => b"3333333432674407958984375 ", 0); | |
289 | check_exact!(f(3.141592f32) => b"31415920257568359375 ", 1); | |
290 | check_exact!(f(3.141592e17f32) => b"314159196796878848 ", 18); | |
291 | check_exact!(f(f32::MAX) => b"34028234663852885981170418348451692544 ", 39); | |
292 | check_exact!(f(f32::MIN_POSITIVE) => b"1175494350822287507968736537222245677818", -37); | |
293 | check_exact!(f(minf32) => b"1401298464324817070923729583289916131280", -44); | |
294 | ||
295 | // [1], Table 16: Stress Inputs for Converting 24-bit Binary to Decimal, < 1/2 ULP | |
296 | check_exact_one!(f(12676506, -102; f32) => b"2", -23); | |
297 | check_exact_one!(f(12676506, -103; f32) => b"12", -23); | |
298 | check_exact_one!(f(15445013, 86; f32) => b"119", 34); | |
299 | check_exact_one!(f(13734123, -138; f32) => b"3941", -34); | |
300 | check_exact_one!(f(12428269, -130; f32) => b"91308", -32); | |
301 | check_exact_one!(f(15334037, -146; f32) => b"171900", -36); | |
302 | check_exact_one!(f(11518287, -41; f32) => b"5237910", -5); | |
303 | check_exact_one!(f(12584953, -145; f32) => b"28216440", -36); | |
304 | check_exact_one!(f(15961084, -125; f32) => b"375243281", -30); | |
305 | check_exact_one!(f(14915817, -146; f32) => b"1672120916", -36); | |
306 | check_exact_one!(f(10845484, -102; f32) => b"21388945814", -23); | |
307 | check_exact_one!(f(16431059, -61; f32) => b"712583594561", -11); | |
308 | ||
309 | // [1], Table 17: Stress Inputs for Converting 24-bit Binary to Decimal, > 1/2 ULP | |
310 | check_exact_one!(f(16093626, 69; f32) => b"1", 29); | |
311 | check_exact_one!(f( 9983778, 25; f32) => b"34", 15); | |
312 | check_exact_one!(f(12745034, 104; f32) => b"259", 39); | |
313 | check_exact_one!(f(12706553, 72; f32) => b"6001", 29); | |
314 | check_exact_one!(f(11005028, 45; f32) => b"38721", 21); | |
315 | check_exact_one!(f(15059547, 71; f32) => b"355584", 29); | |
316 | check_exact_one!(f(16015691, -99; f32) => b"2526831", -22); | |
317 | check_exact_one!(f( 8667859, 56; f32) => b"62458507", 24); | |
318 | check_exact_one!(f(14855922, -82; f32) => b"307213267", -17); | |
319 | check_exact_one!(f(14855922, -83; f32) => b"1536066333", -17); | |
320 | check_exact_one!(f(10144164, -110; f32) => b"78147796834", -26); | |
321 | check_exact_one!(f(13248074, 95; f32) => b"524810279937", 36); | |
322 | } | |
323 | ||
dfeec247 XL |
324 | pub fn f64_shortest_sanity_test<F>(mut f: F) |
325 | where | |
1b1a35ee | 326 | F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> (&'a [u8], i16), |
dfeec247 | 327 | { |
d9579d0f AL |
328 | // 0.0999999999999999777955395074968691915273... |
329 | // 0.1000000000000000055511151231257827021181... | |
330 | // 0.1000000000000000333066907387546962127089... | |
331 | check_shortest!(f(0.1f64) => b"1", 0); | |
332 | ||
333 | // this example is explicitly mentioned in the paper. | |
334 | // 10^3 * 0.0999999999999999857891452847979962825775... | |
335 | // 10^3 * 0.1 (exact) | |
336 | // 10^3 * 0.1000000000000000142108547152020037174224... | |
337 | check_shortest!(f(100.0f64) => b"1", 3); | |
338 | ||
339 | // 0.3333333333333332593184650249895639717578... | |
340 | // 0.3333333333333333148296162562473909929394... (1/3 in the default rounding) | |
341 | // 0.3333333333333333703407674875052180141210... | |
342 | check_shortest!(f(1.0f64/3.0) => b"3333333333333333", 0); | |
343 | ||
344 | // explicit test case for equally closest representations. | |
345 | // Dragon has its own tie-breaking rule; Grisu should fall back. | |
346 | // 10^1 * 0.1000007629394531027955395074968691915273... | |
347 | // 10^1 * 0.100000762939453125 (exact) | |
348 | // 10^1 * 0.1000007629394531472044604925031308084726... | |
349 | check_shortest!(f(1.00000762939453125f64) => b"10000076293945313", 1); | |
350 | ||
351 | // 10^1 * 0.3141591999999999718085064159822650253772... | |
352 | // 10^1 * 0.3141592000000000162174274009885266423225... | |
353 | // 10^1 * 0.3141592000000000606263483859947882592678... | |
354 | check_shortest!(f(3.141592f64) => b"3141592", 1); | |
355 | ||
356 | // 10^18 * 0.314159199999999936 | |
357 | // 10^18 * 0.3141592 (exact) | |
358 | // 10^18 * 0.314159200000000064 | |
359 | check_shortest!(f(3.141592e17f64) => b"3141592", 18); | |
360 | ||
361 | // regression test for decoders | |
362 | // 10^20 * 0.18446744073709549568 | |
363 | // 10^20 * 0.18446744073709551616 | |
364 | // 10^20 * 0.18446744073709555712 | |
3157f602 | 365 | check_shortest!(f(ldexp_f64(1.0, 64)) => b"18446744073709552", 20); |
d9579d0f AL |
366 | |
367 | // pathological case: high = 10^23 (exact). tie breaking should always prefer that. | |
368 | // 10^24 * 0.099999999999999974834176 | |
369 | // 10^24 * 0.099999999999999991611392 | |
370 | // 10^24 * 0.100000000000000008388608 | |
371 | check_shortest!(f(1.0e23f64) => b"1", 24); | |
372 | ||
373 | // 10^309 * 0.1797693134862315508561243283845062402343... | |
374 | // 10^309 * 0.1797693134862315708145274237317043567980... | |
375 | // 10^309 * 0.1797693134862315907729305190789024733617... | |
376 | check_shortest!(f(f64::MAX) => b"17976931348623157", 309); | |
377 | ||
378 | // 10^-307 * 0.2225073858507200889024586876085859887650... | |
379 | // 10^-307 * 0.2225073858507201383090232717332404064219... | |
380 | // 10^-307 * 0.2225073858507201877155878558578948240788... | |
381 | check_shortest!(f(f64::MIN_POSITIVE) => b"22250738585072014", -307); | |
382 | ||
383 | // 10^-323 * 0 | |
384 | // 10^-323 * 0.4940656458412465441765687928682213723650... | |
385 | // 10^-323 * 0.9881312916824930883531375857364427447301... | |
3157f602 | 386 | let minf64 = ldexp_f64(1.0, -1074); |
d9579d0f AL |
387 | check_shortest!(f(minf64) => b"5", -323); |
388 | } | |
389 | ||
390 | pub fn f64_exact_sanity_test<F>(mut f: F) | |
dfeec247 | 391 | where |
1b1a35ee | 392 | F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>], i16) -> (&'a [u8], i16), |
dfeec247 | 393 | { |
3157f602 | 394 | let minf64 = ldexp_f64(1.0, -1074); |
d9579d0f AL |
395 | |
396 | check_exact!(f(0.1f64) => b"1000000000000000055511151231257827021181", 0); | |
397 | check_exact!(f(0.45f64) => b"4500000000000000111022302462515654042363", 0); | |
398 | check_exact!(f(0.5f64) => b"5 ", 0); | |
399 | check_exact!(f(0.95f64) => b"9499999999999999555910790149937383830547", 0); | |
400 | check_exact!(f(100.0f64) => b"1 ", 3); | |
401 | check_exact!(f(999.5f64) => b"9995000000000000000000000000000000000000", 3); | |
402 | check_exact!(f(1.0f64/3.0) => b"3333333333333333148296162562473909929394", 0); | |
403 | check_exact!(f(3.141592f64) => b"3141592000000000162174274009885266423225", 1); | |
404 | check_exact!(f(3.141592e17f64) => b"3141592 ", 18); | |
405 | check_exact!(f(1.0e23f64) => b"99999999999999991611392 ", 23); | |
406 | check_exact!(f(f64::MAX) => b"1797693134862315708145274237317043567980", 309); | |
407 | check_exact!(f(f64::MIN_POSITIVE) => b"2225073858507201383090232717332404064219", -307); | |
408 | check_exact!(f(minf64) => b"4940656458412465441765687928682213723650\ | |
409 | 5980261432476442558568250067550727020875\ | |
410 | 1865299836361635992379796564695445717730\ | |
411 | 9266567103559397963987747960107818781263\ | |
412 | 0071319031140452784581716784898210368871\ | |
413 | 8636056998730723050006387409153564984387\ | |
414 | 3124733972731696151400317153853980741262\ | |
415 | 3856559117102665855668676818703956031062\ | |
416 | 4931945271591492455329305456544401127480\ | |
417 | 1297099995419319894090804165633245247571\ | |
418 | 4786901472678015935523861155013480352649\ | |
419 | 3472019379026810710749170333222684475333\ | |
420 | 5720832431936092382893458368060106011506\ | |
421 | 1698097530783422773183292479049825247307\ | |
422 | 7637592724787465608477820373446969953364\ | |
423 | 7017972677717585125660551199131504891101\ | |
424 | 4510378627381672509558373897335989936648\ | |
425 | 0994116420570263709027924276754456522908\ | |
426 | 7538682506419718265533447265625 ", -323); | |
427 | ||
428 | // [1], Table 3: Stress Inputs for Converting 53-bit Binary to Decimal, < 1/2 ULP | |
429 | check_exact_one!(f(8511030020275656, -342; f64) => b"9", -87); | |
430 | check_exact_one!(f(5201988407066741, -824; f64) => b"46", -232); | |
431 | check_exact_one!(f(6406892948269899, 237; f64) => b"141", 88); | |
432 | check_exact_one!(f(8431154198732492, 72; f64) => b"3981", 38); | |
433 | check_exact_one!(f(6475049196144587, 99; f64) => b"41040", 46); | |
434 | check_exact_one!(f(8274307542972842, 726; f64) => b"292084", 235); | |
435 | check_exact_one!(f(5381065484265332, -456; f64) => b"2891946", -121); | |
436 | check_exact_one!(f(6761728585499734, -1057; f64) => b"43787718", -302); | |
437 | check_exact_one!(f(7976538478610756, 376; f64) => b"122770163", 130); | |
438 | check_exact_one!(f(5982403858958067, 377; f64) => b"1841552452", 130); | |
439 | check_exact_one!(f(5536995190630837, 93; f64) => b"54835744350", 44); | |
440 | check_exact_one!(f(7225450889282194, 710; f64) => b"389190181146", 230); | |
441 | check_exact_one!(f(7225450889282194, 709; f64) => b"1945950905732", 230); | |
442 | check_exact_one!(f(8703372741147379, 117; f64) => b"14460958381605", 52); | |
443 | check_exact_one!(f(8944262675275217, -1001; f64) => b"417367747458531", -285); | |
444 | check_exact_one!(f(7459803696087692, -707; f64) => b"1107950772878888", -196); | |
445 | check_exact_one!(f(6080469016670379, -381; f64) => b"12345501366327440", -98); | |
446 | check_exact_one!(f(8385515147034757, 721; f64) => b"925031711960365024", 233); | |
447 | check_exact_one!(f(7514216811389786, -828; f64) => b"4198047150284889840", -233); | |
448 | check_exact_one!(f(8397297803260511, -345; f64) => b"11716315319786511046", -87); | |
449 | check_exact_one!(f(6733459239310543, 202; f64) => b"432810072844612493629", 77); | |
450 | check_exact_one!(f(8091450587292794, -473; f64) => b"3317710118160031081518", -126); | |
451 | ||
452 | // [1], Table 4: Stress Inputs for Converting 53-bit Binary to Decimal, > 1/2 ULP | |
453 | check_exact_one!(f(6567258882077402, 952; f64) => b"3", 303); | |
454 | check_exact_one!(f(6712731423444934, 535; f64) => b"76", 177); | |
455 | check_exact_one!(f(6712731423444934, 534; f64) => b"378", 177); | |
456 | check_exact_one!(f(5298405411573037, -957; f64) => b"4350", -272); | |
457 | check_exact_one!(f(5137311167659507, -144; f64) => b"23037", -27); | |
458 | check_exact_one!(f(6722280709661868, 363; f64) => b"126301", 126); | |
459 | check_exact_one!(f(5344436398034927, -169; f64) => b"7142211", -35); | |
460 | check_exact_one!(f(8369123604277281, -853; f64) => b"13934574", -240); | |
461 | check_exact_one!(f(8995822108487663, -780; f64) => b"141463449", -218); | |
462 | check_exact_one!(f(8942832835564782, -383; f64) => b"4539277920", -99); | |
463 | check_exact_one!(f(8942832835564782, -384; f64) => b"22696389598", -99); | |
464 | check_exact_one!(f(8942832835564782, -385; f64) => b"113481947988", -99); | |
465 | check_exact_one!(f(6965949469487146, -249; f64) => b"7700366561890", -59); | |
466 | check_exact_one!(f(6965949469487146, -250; f64) => b"38501832809448", -59); | |
467 | check_exact_one!(f(6965949469487146, -251; f64) => b"192509164047238", -59); | |
468 | check_exact_one!(f(7487252720986826, 548; f64) => b"6898586531774201", 181); | |
469 | check_exact_one!(f(5592117679628511, 164; f64) => b"13076622631878654", 66); | |
470 | check_exact_one!(f(8887055249355788, 665; f64) => b"136052020756121240", 217); | |
471 | check_exact_one!(f(6994187472632449, 690; f64) => b"3592810217475959676", 224); | |
472 | check_exact_one!(f(8797576579012143, 588; f64) => b"89125197712484551899", 193); | |
473 | check_exact_one!(f(7363326733505337, 272; f64) => b"558769757362301140950", 98); | |
474 | check_exact_one!(f(8549497411294502, -448; f64) => b"1176257830728540379990", -118); | |
475 | } | |
476 | ||
dfeec247 XL |
477 | pub fn more_shortest_sanity_test<F>(mut f: F) |
478 | where | |
1b1a35ee | 479 | F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> (&'a [u8], i16), |
dfeec247 | 480 | { |
d9579d0f AL |
481 | check_shortest!(f{mant: 99_999_999_999_999_999, minus: 1, plus: 1, |
482 | exp: 0, inclusive: true} => b"1", 18); | |
483 | check_shortest!(f{mant: 99_999_999_999_999_999, minus: 1, plus: 1, | |
484 | exp: 0, inclusive: false} => b"99999999999999999", 17); | |
485 | } | |
486 | ||
d9579d0f | 487 | fn to_string_with_parts<F>(mut f: F) -> String |
dfeec247 | 488 | where |
1b1a35ee | 489 | F: for<'a> FnMut(&'a mut [MaybeUninit<u8>], &'a mut [MaybeUninit<Part<'a>>]) -> Formatted<'a>, |
dfeec247 | 490 | { |
1b1a35ee XL |
491 | let mut buf = [MaybeUninit::new(0); 1024]; |
492 | let mut parts = [MaybeUninit::new(Part::Zero(0)); 16]; | |
d9579d0f AL |
493 | let formatted = f(&mut buf, &mut parts); |
494 | let mut ret = vec![0; formatted.len()]; | |
495 | assert_eq!(formatted.write(&mut ret), Some(ret.len())); | |
496 | String::from_utf8(ret).unwrap() | |
497 | } | |
498 | ||
499 | pub fn to_shortest_str_test<F>(mut f_: F) | |
dfeec247 | 500 | where |
1b1a35ee | 501 | F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> (&'a [u8], i16), |
dfeec247 | 502 | { |
d9579d0f AL |
503 | use core::num::flt2dec::Sign::*; |
504 | ||
74b04a01 | 505 | fn to_string<T, F>(f: &mut F, v: T, sign: Sign, frac_digits: usize) -> String |
dfeec247 XL |
506 | where |
507 | T: DecodableFloat, | |
1b1a35ee | 508 | F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> (&'a [u8], i16), |
dfeec247 XL |
509 | { |
510 | to_string_with_parts(|buf, parts| { | |
74b04a01 | 511 | to_shortest_str(|d, b| f(d, b), v, sign, frac_digits, buf, parts) |
dfeec247 | 512 | }) |
d9579d0f AL |
513 | } |
514 | ||
515 | let f = &mut f_; | |
516 | ||
74b04a01 | 517 | assert_eq!(to_string(f, 0.0, Minus, 0), "0"); |
cdc7bbd5 | 518 | assert_eq!(to_string(f, 0.0, Minus, 0), "0"); |
74b04a01 | 519 | assert_eq!(to_string(f, 0.0, MinusPlus, 0), "+0"); |
cdc7bbd5 XL |
520 | assert_eq!(to_string(f, -0.0, Minus, 0), "-0"); |
521 | assert_eq!(to_string(f, -0.0, MinusPlus, 0), "-0"); | |
522 | assert_eq!(to_string(f, 0.0, Minus, 1), "0.0"); | |
74b04a01 | 523 | assert_eq!(to_string(f, 0.0, Minus, 1), "0.0"); |
74b04a01 | 524 | assert_eq!(to_string(f, 0.0, MinusPlus, 1), "+0.0"); |
cdc7bbd5 XL |
525 | assert_eq!(to_string(f, -0.0, Minus, 8), "-0.00000000"); |
526 | assert_eq!(to_string(f, -0.0, MinusPlus, 8), "-0.00000000"); | |
74b04a01 XL |
527 | |
528 | assert_eq!(to_string(f, 1.0 / 0.0, Minus, 0), "inf"); | |
cdc7bbd5 | 529 | assert_eq!(to_string(f, 1.0 / 0.0, Minus, 0), "inf"); |
74b04a01 | 530 | assert_eq!(to_string(f, 1.0 / 0.0, MinusPlus, 0), "+inf"); |
74b04a01 | 531 | assert_eq!(to_string(f, 0.0 / 0.0, Minus, 0), "NaN"); |
cdc7bbd5 XL |
532 | assert_eq!(to_string(f, 0.0 / 0.0, Minus, 1), "NaN"); |
533 | assert_eq!(to_string(f, 0.0 / 0.0, MinusPlus, 64), "NaN"); | |
74b04a01 | 534 | assert_eq!(to_string(f, -1.0 / 0.0, Minus, 0), "-inf"); |
cdc7bbd5 XL |
535 | assert_eq!(to_string(f, -1.0 / 0.0, Minus, 1), "-inf"); |
536 | assert_eq!(to_string(f, -1.0 / 0.0, MinusPlus, 64), "-inf"); | |
74b04a01 XL |
537 | |
538 | assert_eq!(to_string(f, 3.14, Minus, 0), "3.14"); | |
cdc7bbd5 | 539 | assert_eq!(to_string(f, 3.14, Minus, 0), "3.14"); |
74b04a01 | 540 | assert_eq!(to_string(f, 3.14, MinusPlus, 0), "+3.14"); |
74b04a01 | 541 | assert_eq!(to_string(f, -3.14, Minus, 0), "-3.14"); |
cdc7bbd5 | 542 | assert_eq!(to_string(f, -3.14, Minus, 0), "-3.14"); |
74b04a01 | 543 | assert_eq!(to_string(f, -3.14, MinusPlus, 0), "-3.14"); |
74b04a01 | 544 | assert_eq!(to_string(f, 3.14, Minus, 1), "3.14"); |
cdc7bbd5 XL |
545 | assert_eq!(to_string(f, 3.14, Minus, 2), "3.14"); |
546 | assert_eq!(to_string(f, 3.14, MinusPlus, 4), "+3.1400"); | |
547 | assert_eq!(to_string(f, -3.14, Minus, 8), "-3.14000000"); | |
74b04a01 | 548 | assert_eq!(to_string(f, -3.14, Minus, 8), "-3.14000000"); |
74b04a01 | 549 | assert_eq!(to_string(f, -3.14, MinusPlus, 8), "-3.14000000"); |
74b04a01 XL |
550 | |
551 | assert_eq!(to_string(f, 7.5e-11, Minus, 0), "0.000000000075"); | |
552 | assert_eq!(to_string(f, 7.5e-11, Minus, 3), "0.000000000075"); | |
553 | assert_eq!(to_string(f, 7.5e-11, Minus, 12), "0.000000000075"); | |
554 | assert_eq!(to_string(f, 7.5e-11, Minus, 13), "0.0000000000750"); | |
555 | ||
556 | assert_eq!(to_string(f, 1.9971e20, Minus, 0), "199710000000000000000"); | |
557 | assert_eq!(to_string(f, 1.9971e20, Minus, 1), "199710000000000000000.0"); | |
558 | assert_eq!(to_string(f, 1.9971e20, Minus, 8), "199710000000000000000.00000000"); | |
559 | ||
560 | assert_eq!(to_string(f, f32::MAX, Minus, 0), format!("34028235{:0>31}", "")); | |
561 | assert_eq!(to_string(f, f32::MAX, Minus, 1), format!("34028235{:0>31}.0", "")); | |
562 | assert_eq!(to_string(f, f32::MAX, Minus, 8), format!("34028235{:0>31}.00000000", "")); | |
d9579d0f | 563 | |
3157f602 | 564 | let minf32 = ldexp_f32(1.0, -149); |
74b04a01 XL |
565 | assert_eq!(to_string(f, minf32, Minus, 0), format!("0.{:0>44}1", "")); |
566 | assert_eq!(to_string(f, minf32, Minus, 45), format!("0.{:0>44}1", "")); | |
567 | assert_eq!(to_string(f, minf32, Minus, 46), format!("0.{:0>44}10", "")); | |
d9579d0f | 568 | |
74b04a01 XL |
569 | assert_eq!(to_string(f, f64::MAX, Minus, 0), format!("17976931348623157{:0>292}", "")); |
570 | assert_eq!(to_string(f, f64::MAX, Minus, 1), format!("17976931348623157{:0>292}.0", "")); | |
571 | assert_eq!(to_string(f, f64::MAX, Minus, 8), format!("17976931348623157{:0>292}.00000000", "")); | |
d9579d0f | 572 | |
3157f602 | 573 | let minf64 = ldexp_f64(1.0, -1074); |
74b04a01 XL |
574 | assert_eq!(to_string(f, minf64, Minus, 0), format!("0.{:0>323}5", "")); |
575 | assert_eq!(to_string(f, minf64, Minus, 324), format!("0.{:0>323}5", "")); | |
576 | assert_eq!(to_string(f, minf64, Minus, 325), format!("0.{:0>323}50", "")); | |
d9579d0f | 577 | |
dfeec247 XL |
578 | if cfg!(miri) { |
579 | // Miri is too slow | |
416331ca XL |
580 | return; |
581 | } | |
582 | ||
d9579d0f | 583 | // very large output |
74b04a01 | 584 | assert_eq!(to_string(f, 1.1, Minus, 80000), format!("1.1{:0>79999}", "")); |
d9579d0f AL |
585 | } |
586 | ||
587 | pub fn to_shortest_exp_str_test<F>(mut f_: F) | |
dfeec247 | 588 | where |
1b1a35ee | 589 | F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> (&'a [u8], i16), |
dfeec247 | 590 | { |
d9579d0f AL |
591 | use core::num::flt2dec::Sign::*; |
592 | ||
593 | fn to_string<T, F>(f: &mut F, v: T, sign: Sign, exp_bounds: (i16, i16), upper: bool) -> String | |
dfeec247 XL |
594 | where |
595 | T: DecodableFloat, | |
1b1a35ee | 596 | F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> (&'a [u8], i16), |
dfeec247 XL |
597 | { |
598 | to_string_with_parts(|buf, parts| { | |
599 | to_shortest_exp_str(|d, b| f(d, b), v, sign, exp_bounds, upper, buf, parts) | |
600 | }) | |
d9579d0f AL |
601 | } |
602 | ||
603 | let f = &mut f_; | |
604 | ||
dfeec247 | 605 | assert_eq!(to_string(f, 0.0, Minus, (-4, 16), false), "0"); |
cdc7bbd5 | 606 | assert_eq!(to_string(f, 0.0, Minus, (-4, 16), false), "0"); |
dfeec247 | 607 | assert_eq!(to_string(f, 0.0, MinusPlus, (-4, 16), false), "+0"); |
cdc7bbd5 XL |
608 | assert_eq!(to_string(f, -0.0, Minus, (-4, 16), false), "-0"); |
609 | assert_eq!(to_string(f, -0.0, MinusPlus, (-4, 16), false), "-0"); | |
dfeec247 | 610 | assert_eq!(to_string(f, 0.0, Minus, (0, 0), true), "0E0"); |
cdc7bbd5 XL |
611 | assert_eq!(to_string(f, 0.0, Minus, (0, 0), false), "0e0"); |
612 | assert_eq!(to_string(f, 0.0, MinusPlus, (5, 9), false), "+0e0"); | |
613 | assert_eq!(to_string(f, -0.0, Minus, (0, 0), true), "-0E0"); | |
614 | assert_eq!(to_string(f, -0.0, MinusPlus, (5, 9), false), "-0e0"); | |
dfeec247 XL |
615 | |
616 | assert_eq!(to_string(f, 1.0 / 0.0, Minus, (-4, 16), false), "inf"); | |
cdc7bbd5 XL |
617 | assert_eq!(to_string(f, 1.0 / 0.0, Minus, (-4, 16), true), "inf"); |
618 | assert_eq!(to_string(f, 1.0 / 0.0, MinusPlus, (-4, 16), true), "+inf"); | |
dfeec247 | 619 | assert_eq!(to_string(f, 0.0 / 0.0, Minus, (0, 0), false), "NaN"); |
cdc7bbd5 XL |
620 | assert_eq!(to_string(f, 0.0 / 0.0, Minus, (0, 0), true), "NaN"); |
621 | assert_eq!(to_string(f, 0.0 / 0.0, MinusPlus, (5, 9), true), "NaN"); | |
dfeec247 | 622 | assert_eq!(to_string(f, -1.0 / 0.0, Minus, (0, 0), false), "-inf"); |
cdc7bbd5 XL |
623 | assert_eq!(to_string(f, -1.0 / 0.0, Minus, (0, 0), true), "-inf"); |
624 | assert_eq!(to_string(f, -1.0 / 0.0, MinusPlus, (5, 9), true), "-inf"); | |
dfeec247 XL |
625 | |
626 | assert_eq!(to_string(f, 3.14, Minus, (-4, 16), false), "3.14"); | |
dfeec247 | 627 | assert_eq!(to_string(f, 3.14, MinusPlus, (-4, 16), false), "+3.14"); |
dfeec247 | 628 | assert_eq!(to_string(f, -3.14, Minus, (-4, 16), false), "-3.14"); |
dfeec247 | 629 | assert_eq!(to_string(f, -3.14, MinusPlus, (-4, 16), false), "-3.14"); |
dfeec247 | 630 | assert_eq!(to_string(f, 3.14, Minus, (0, 0), true), "3.14E0"); |
cdc7bbd5 XL |
631 | assert_eq!(to_string(f, 3.14, Minus, (0, 0), false), "3.14e0"); |
632 | assert_eq!(to_string(f, 3.14, MinusPlus, (5, 9), false), "+3.14e0"); | |
dfeec247 | 633 | assert_eq!(to_string(f, -3.14, Minus, (0, 0), true), "-3.14E0"); |
cdc7bbd5 XL |
634 | assert_eq!(to_string(f, -3.14, Minus, (0, 0), false), "-3.14e0"); |
635 | assert_eq!(to_string(f, -3.14, MinusPlus, (5, 9), false), "-3.14e0"); | |
dfeec247 XL |
636 | |
637 | assert_eq!(to_string(f, 0.1, Minus, (-4, 16), false), "0.1"); | |
cdc7bbd5 | 638 | assert_eq!(to_string(f, 0.1, Minus, (-4, 16), false), "0.1"); |
dfeec247 | 639 | assert_eq!(to_string(f, 0.1, MinusPlus, (-4, 16), false), "+0.1"); |
dfeec247 | 640 | assert_eq!(to_string(f, -0.1, Minus, (-4, 16), false), "-0.1"); |
dfeec247 | 641 | assert_eq!(to_string(f, -0.1, MinusPlus, (-4, 16), false), "-0.1"); |
dfeec247 | 642 | assert_eq!(to_string(f, 0.1, Minus, (0, 0), true), "1E-1"); |
cdc7bbd5 XL |
643 | assert_eq!(to_string(f, 0.1, Minus, (0, 0), false), "1e-1"); |
644 | assert_eq!(to_string(f, 0.1, MinusPlus, (5, 9), false), "+1e-1"); | |
dfeec247 | 645 | assert_eq!(to_string(f, -0.1, Minus, (0, 0), true), "-1E-1"); |
cdc7bbd5 XL |
646 | assert_eq!(to_string(f, -0.1, Minus, (0, 0), false), "-1e-1"); |
647 | assert_eq!(to_string(f, -0.1, MinusPlus, (5, 9), false), "-1e-1"); | |
dfeec247 XL |
648 | |
649 | assert_eq!(to_string(f, 7.5e-11, Minus, (-4, 16), false), "7.5e-11"); | |
d9579d0f AL |
650 | assert_eq!(to_string(f, 7.5e-11, Minus, (-11, 10), false), "0.000000000075"); |
651 | assert_eq!(to_string(f, 7.5e-11, Minus, (-10, 11), false), "7.5e-11"); | |
652 | ||
dfeec247 | 653 | assert_eq!(to_string(f, 1.9971e20, Minus, (-4, 16), false), "1.9971e20"); |
d9579d0f AL |
654 | assert_eq!(to_string(f, 1.9971e20, Minus, (-20, 21), false), "199710000000000000000"); |
655 | assert_eq!(to_string(f, 1.9971e20, Minus, (-21, 20), false), "1.9971e20"); | |
656 | ||
657 | // the true value of 1.0e23f64 is less than 10^23, but that shouldn't matter here | |
658 | assert_eq!(to_string(f, 1.0e23, Minus, (22, 23), false), "1e23"); | |
659 | assert_eq!(to_string(f, 1.0e23, Minus, (23, 24), false), "100000000000000000000000"); | |
660 | assert_eq!(to_string(f, 1.0e23, Minus, (24, 25), false), "1e23"); | |
661 | ||
dfeec247 | 662 | assert_eq!(to_string(f, f32::MAX, Minus, (-4, 16), false), "3.4028235e38"); |
d9579d0f AL |
663 | assert_eq!(to_string(f, f32::MAX, Minus, (-39, 38), false), "3.4028235e38"); |
664 | assert_eq!(to_string(f, f32::MAX, Minus, (-38, 39), false), format!("34028235{:0>31}", "")); | |
665 | ||
3157f602 | 666 | let minf32 = ldexp_f32(1.0, -149); |
dfeec247 | 667 | assert_eq!(to_string(f, minf32, Minus, (-4, 16), false), "1e-45"); |
d9579d0f AL |
668 | assert_eq!(to_string(f, minf32, Minus, (-44, 45), false), "1e-45"); |
669 | assert_eq!(to_string(f, minf32, Minus, (-45, 44), false), format!("0.{:0>44}1", "")); | |
670 | ||
dfeec247 XL |
671 | assert_eq!(to_string(f, f64::MAX, Minus, (-4, 16), false), "1.7976931348623157e308"); |
672 | assert_eq!( | |
673 | to_string(f, f64::MAX, Minus, (-308, 309), false), | |
674 | format!("17976931348623157{:0>292}", "") | |
675 | ); | |
676 | assert_eq!(to_string(f, f64::MAX, Minus, (-309, 308), false), "1.7976931348623157e308"); | |
d9579d0f | 677 | |
3157f602 | 678 | let minf64 = ldexp_f64(1.0, -1074); |
dfeec247 | 679 | assert_eq!(to_string(f, minf64, Minus, (-4, 16), false), "5e-324"); |
d9579d0f AL |
680 | assert_eq!(to_string(f, minf64, Minus, (-324, 323), false), format!("0.{:0>323}5", "")); |
681 | assert_eq!(to_string(f, minf64, Minus, (-323, 324), false), "5e-324"); | |
682 | ||
683 | assert_eq!(to_string(f, 1.1, Minus, (i16::MIN, i16::MAX), false), "1.1"); | |
684 | } | |
685 | ||
686 | pub fn to_exact_exp_str_test<F>(mut f_: F) | |
dfeec247 | 687 | where |
1b1a35ee | 688 | F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>], i16) -> (&'a [u8], i16), |
dfeec247 | 689 | { |
d9579d0f AL |
690 | use core::num::flt2dec::Sign::*; |
691 | ||
692 | fn to_string<T, F>(f: &mut F, v: T, sign: Sign, ndigits: usize, upper: bool) -> String | |
dfeec247 XL |
693 | where |
694 | T: DecodableFloat, | |
1b1a35ee | 695 | F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>], i16) -> (&'a [u8], i16), |
dfeec247 XL |
696 | { |
697 | to_string_with_parts(|buf, parts| { | |
698 | to_exact_exp_str(|d, b, l| f(d, b, l), v, sign, ndigits, upper, buf, parts) | |
699 | }) | |
d9579d0f AL |
700 | } |
701 | ||
702 | let f = &mut f_; | |
703 | ||
dfeec247 | 704 | assert_eq!(to_string(f, 0.0, Minus, 1, true), "0E0"); |
cdc7bbd5 XL |
705 | assert_eq!(to_string(f, 0.0, Minus, 1, false), "0e0"); |
706 | assert_eq!(to_string(f, 0.0, MinusPlus, 1, false), "+0e0"); | |
707 | assert_eq!(to_string(f, -0.0, Minus, 1, true), "-0E0"); | |
708 | assert_eq!(to_string(f, -0.0, MinusPlus, 1, false), "-0e0"); | |
dfeec247 | 709 | assert_eq!(to_string(f, 0.0, Minus, 2, true), "0.0E0"); |
cdc7bbd5 XL |
710 | assert_eq!(to_string(f, 0.0, Minus, 2, false), "0.0e0"); |
711 | assert_eq!(to_string(f, 0.0, MinusPlus, 2, false), "+0.0e0"); | |
712 | assert_eq!(to_string(f, -0.0, Minus, 8, false), "-0.0000000e0"); | |
713 | assert_eq!(to_string(f, -0.0, MinusPlus, 8, false), "-0.0000000e0"); | |
d9579d0f | 714 | |
dfeec247 | 715 | assert_eq!(to_string(f, 1.0 / 0.0, Minus, 1, false), "inf"); |
cdc7bbd5 XL |
716 | assert_eq!(to_string(f, 1.0 / 0.0, Minus, 1, true), "inf"); |
717 | assert_eq!(to_string(f, 1.0 / 0.0, MinusPlus, 1, true), "+inf"); | |
dfeec247 | 718 | assert_eq!(to_string(f, 0.0 / 0.0, Minus, 8, false), "NaN"); |
cdc7bbd5 XL |
719 | assert_eq!(to_string(f, 0.0 / 0.0, Minus, 8, true), "NaN"); |
720 | assert_eq!(to_string(f, 0.0 / 0.0, MinusPlus, 8, true), "NaN"); | |
dfeec247 | 721 | assert_eq!(to_string(f, -1.0 / 0.0, Minus, 64, false), "-inf"); |
cdc7bbd5 XL |
722 | assert_eq!(to_string(f, -1.0 / 0.0, Minus, 64, true), "-inf"); |
723 | assert_eq!(to_string(f, -1.0 / 0.0, MinusPlus, 64, true), "-inf"); | |
dfeec247 XL |
724 | |
725 | assert_eq!(to_string(f, 3.14, Minus, 1, true), "3E0"); | |
cdc7bbd5 XL |
726 | assert_eq!(to_string(f, 3.14, Minus, 1, false), "3e0"); |
727 | assert_eq!(to_string(f, 3.14, MinusPlus, 1, false), "+3e0"); | |
dfeec247 | 728 | assert_eq!(to_string(f, -3.14, Minus, 2, true), "-3.1E0"); |
cdc7bbd5 XL |
729 | assert_eq!(to_string(f, -3.14, Minus, 2, false), "-3.1e0"); |
730 | assert_eq!(to_string(f, -3.14, MinusPlus, 2, false), "-3.1e0"); | |
dfeec247 | 731 | assert_eq!(to_string(f, 3.14, Minus, 3, true), "3.14E0"); |
cdc7bbd5 XL |
732 | assert_eq!(to_string(f, 3.14, Minus, 3, false), "3.14e0"); |
733 | assert_eq!(to_string(f, 3.14, MinusPlus, 3, false), "+3.14e0"); | |
dfeec247 | 734 | assert_eq!(to_string(f, -3.14, Minus, 4, true), "-3.140E0"); |
cdc7bbd5 XL |
735 | assert_eq!(to_string(f, -3.14, Minus, 4, false), "-3.140e0"); |
736 | assert_eq!(to_string(f, -3.14, MinusPlus, 4, false), "-3.140e0"); | |
d9579d0f | 737 | |
dfeec247 | 738 | assert_eq!(to_string(f, 0.195, Minus, 1, false), "2e-1"); |
cdc7bbd5 XL |
739 | assert_eq!(to_string(f, 0.195, Minus, 1, true), "2E-1"); |
740 | assert_eq!(to_string(f, 0.195, MinusPlus, 1, true), "+2E-1"); | |
dfeec247 | 741 | assert_eq!(to_string(f, -0.195, Minus, 2, false), "-2.0e-1"); |
cdc7bbd5 XL |
742 | assert_eq!(to_string(f, -0.195, Minus, 2, true), "-2.0E-1"); |
743 | assert_eq!(to_string(f, -0.195, MinusPlus, 2, true), "-2.0E-1"); | |
dfeec247 | 744 | assert_eq!(to_string(f, 0.195, Minus, 3, false), "1.95e-1"); |
cdc7bbd5 XL |
745 | assert_eq!(to_string(f, 0.195, Minus, 3, true), "1.95E-1"); |
746 | assert_eq!(to_string(f, 0.195, MinusPlus, 3, true), "+1.95E-1"); | |
dfeec247 | 747 | assert_eq!(to_string(f, -0.195, Minus, 4, false), "-1.950e-1"); |
cdc7bbd5 XL |
748 | assert_eq!(to_string(f, -0.195, Minus, 4, true), "-1.950E-1"); |
749 | assert_eq!(to_string(f, -0.195, MinusPlus, 4, true), "-1.950E-1"); | |
dfeec247 XL |
750 | |
751 | assert_eq!(to_string(f, 9.5, Minus, 1, false), "1e1"); | |
752 | assert_eq!(to_string(f, 9.5, Minus, 2, false), "9.5e0"); | |
753 | assert_eq!(to_string(f, 9.5, Minus, 3, false), "9.50e0"); | |
d9579d0f AL |
754 | assert_eq!(to_string(f, 9.5, Minus, 30, false), "9.50000000000000000000000000000e0"); |
755 | ||
dfeec247 XL |
756 | assert_eq!(to_string(f, 1.0e25, Minus, 1, false), "1e25"); |
757 | assert_eq!(to_string(f, 1.0e25, Minus, 2, false), "1.0e25"); | |
d9579d0f AL |
758 | assert_eq!(to_string(f, 1.0e25, Minus, 15, false), "1.00000000000000e25"); |
759 | assert_eq!(to_string(f, 1.0e25, Minus, 16, false), "1.000000000000000e25"); | |
760 | assert_eq!(to_string(f, 1.0e25, Minus, 17, false), "1.0000000000000001e25"); | |
761 | assert_eq!(to_string(f, 1.0e25, Minus, 18, false), "1.00000000000000009e25"); | |
762 | assert_eq!(to_string(f, 1.0e25, Minus, 19, false), "1.000000000000000091e25"); | |
763 | assert_eq!(to_string(f, 1.0e25, Minus, 20, false), "1.0000000000000000906e25"); | |
764 | assert_eq!(to_string(f, 1.0e25, Minus, 21, false), "1.00000000000000009060e25"); | |
765 | assert_eq!(to_string(f, 1.0e25, Minus, 22, false), "1.000000000000000090597e25"); | |
766 | assert_eq!(to_string(f, 1.0e25, Minus, 23, false), "1.0000000000000000905970e25"); | |
767 | assert_eq!(to_string(f, 1.0e25, Minus, 24, false), "1.00000000000000009059697e25"); | |
768 | assert_eq!(to_string(f, 1.0e25, Minus, 25, false), "1.000000000000000090596966e25"); | |
769 | assert_eq!(to_string(f, 1.0e25, Minus, 26, false), "1.0000000000000000905969664e25"); | |
770 | assert_eq!(to_string(f, 1.0e25, Minus, 27, false), "1.00000000000000009059696640e25"); | |
771 | assert_eq!(to_string(f, 1.0e25, Minus, 30, false), "1.00000000000000009059696640000e25"); | |
772 | ||
dfeec247 XL |
773 | assert_eq!(to_string(f, 1.0e-6, Minus, 1, false), "1e-6"); |
774 | assert_eq!(to_string(f, 1.0e-6, Minus, 2, false), "1.0e-6"); | |
d9579d0f AL |
775 | assert_eq!(to_string(f, 1.0e-6, Minus, 16, false), "1.000000000000000e-6"); |
776 | assert_eq!(to_string(f, 1.0e-6, Minus, 17, false), "9.9999999999999995e-7"); | |
777 | assert_eq!(to_string(f, 1.0e-6, Minus, 18, false), "9.99999999999999955e-7"); | |
778 | assert_eq!(to_string(f, 1.0e-6, Minus, 19, false), "9.999999999999999547e-7"); | |
779 | assert_eq!(to_string(f, 1.0e-6, Minus, 20, false), "9.9999999999999995475e-7"); | |
780 | assert_eq!(to_string(f, 1.0e-6, Minus, 30, false), "9.99999999999999954748111825886e-7"); | |
dfeec247 XL |
781 | assert_eq!( |
782 | to_string(f, 1.0e-6, Minus, 40, false), | |
783 | "9.999999999999999547481118258862586856139e-7" | |
784 | ); | |
785 | assert_eq!( | |
786 | to_string(f, 1.0e-6, Minus, 50, false), | |
787 | "9.9999999999999995474811182588625868561393872369081e-7" | |
788 | ); | |
789 | assert_eq!( | |
790 | to_string(f, 1.0e-6, Minus, 60, false), | |
791 | "9.99999999999999954748111825886258685613938723690807819366455e-7" | |
792 | ); | |
793 | assert_eq!( | |
794 | to_string(f, 1.0e-6, Minus, 70, false), | |
795 | "9.999999999999999547481118258862586856139387236908078193664550781250000e-7" | |
796 | ); | |
797 | ||
798 | assert_eq!(to_string(f, f32::MAX, Minus, 1, false), "3e38"); | |
799 | assert_eq!(to_string(f, f32::MAX, Minus, 2, false), "3.4e38"); | |
800 | assert_eq!(to_string(f, f32::MAX, Minus, 4, false), "3.403e38"); | |
801 | assert_eq!(to_string(f, f32::MAX, Minus, 8, false), "3.4028235e38"); | |
d9579d0f AL |
802 | assert_eq!(to_string(f, f32::MAX, Minus, 16, false), "3.402823466385289e38"); |
803 | assert_eq!(to_string(f, f32::MAX, Minus, 32, false), "3.4028234663852885981170418348452e38"); | |
dfeec247 XL |
804 | assert_eq!( |
805 | to_string(f, f32::MAX, Minus, 64, false), | |
806 | "3.402823466385288598117041834845169254400000000000000000000000000e38" | |
807 | ); | |
d9579d0f | 808 | |
3157f602 | 809 | let minf32 = ldexp_f32(1.0, -149); |
dfeec247 XL |
810 | assert_eq!(to_string(f, minf32, Minus, 1, false), "1e-45"); |
811 | assert_eq!(to_string(f, minf32, Minus, 2, false), "1.4e-45"); | |
812 | assert_eq!(to_string(f, minf32, Minus, 4, false), "1.401e-45"); | |
813 | assert_eq!(to_string(f, minf32, Minus, 8, false), "1.4012985e-45"); | |
814 | assert_eq!(to_string(f, minf32, Minus, 16, false), "1.401298464324817e-45"); | |
815 | assert_eq!(to_string(f, minf32, Minus, 32, false), "1.4012984643248170709237295832899e-45"); | |
816 | assert_eq!( | |
817 | to_string(f, minf32, Minus, 64, false), | |
818 | "1.401298464324817070923729583289916131280261941876515771757068284e-45" | |
819 | ); | |
820 | assert_eq!( | |
821 | to_string(f, minf32, Minus, 128, false), | |
822 | "1.401298464324817070923729583289916131280261941876515771757068283\ | |
823 | 8897910826858606014866381883621215820312500000000000000000000000e-45" | |
824 | ); | |
825 | ||
826 | if cfg!(miri) { | |
827 | // Miri is too slow | |
416331ca XL |
828 | return; |
829 | } | |
830 | ||
dfeec247 XL |
831 | assert_eq!(to_string(f, f64::MAX, Minus, 1, false), "2e308"); |
832 | assert_eq!(to_string(f, f64::MAX, Minus, 2, false), "1.8e308"); | |
833 | assert_eq!(to_string(f, f64::MAX, Minus, 4, false), "1.798e308"); | |
834 | assert_eq!(to_string(f, f64::MAX, Minus, 8, false), "1.7976931e308"); | |
835 | assert_eq!(to_string(f, f64::MAX, Minus, 16, false), "1.797693134862316e308"); | |
836 | assert_eq!(to_string(f, f64::MAX, Minus, 32, false), "1.7976931348623157081452742373170e308"); | |
837 | assert_eq!( | |
838 | to_string(f, f64::MAX, Minus, 64, false), | |
839 | "1.797693134862315708145274237317043567980705675258449965989174768e308" | |
840 | ); | |
841 | assert_eq!( | |
842 | to_string(f, f64::MAX, Minus, 128, false), | |
843 | "1.797693134862315708145274237317043567980705675258449965989174768\ | |
844 | 0315726078002853876058955863276687817154045895351438246423432133e308" | |
845 | ); | |
846 | assert_eq!( | |
847 | to_string(f, f64::MAX, Minus, 256, false), | |
848 | "1.797693134862315708145274237317043567980705675258449965989174768\ | |
d9579d0f AL |
849 | 0315726078002853876058955863276687817154045895351438246423432132\ |
850 | 6889464182768467546703537516986049910576551282076245490090389328\ | |
dfeec247 XL |
851 | 9440758685084551339423045832369032229481658085593321233482747978e308" |
852 | ); | |
853 | assert_eq!( | |
854 | to_string(f, f64::MAX, Minus, 512, false), | |
855 | "1.797693134862315708145274237317043567980705675258449965989174768\ | |
d9579d0f AL |
856 | 0315726078002853876058955863276687817154045895351438246423432132\ |
857 | 6889464182768467546703537516986049910576551282076245490090389328\ | |
858 | 9440758685084551339423045832369032229481658085593321233482747978\ | |
859 | 2620414472316873817718091929988125040402618412485836800000000000\ | |
860 | 0000000000000000000000000000000000000000000000000000000000000000\ | |
861 | 0000000000000000000000000000000000000000000000000000000000000000\ | |
dfeec247 XL |
862 | 0000000000000000000000000000000000000000000000000000000000000000e308" |
863 | ); | |
d9579d0f AL |
864 | |
865 | // okay, this is becoming tough. fortunately for us, this is almost the worst case. | |
3157f602 | 866 | let minf64 = ldexp_f64(1.0, -1074); |
dfeec247 XL |
867 | assert_eq!(to_string(f, minf64, Minus, 1, false), "5e-324"); |
868 | assert_eq!(to_string(f, minf64, Minus, 2, false), "4.9e-324"); | |
869 | assert_eq!(to_string(f, minf64, Minus, 4, false), "4.941e-324"); | |
870 | assert_eq!(to_string(f, minf64, Minus, 8, false), "4.9406565e-324"); | |
871 | assert_eq!(to_string(f, minf64, Minus, 16, false), "4.940656458412465e-324"); | |
872 | assert_eq!(to_string(f, minf64, Minus, 32, false), "4.9406564584124654417656879286822e-324"); | |
873 | assert_eq!( | |
874 | to_string(f, minf64, Minus, 64, false), | |
875 | "4.940656458412465441765687928682213723650598026143247644255856825e-324" | |
876 | ); | |
877 | assert_eq!( | |
878 | to_string(f, minf64, Minus, 128, false), | |
879 | "4.940656458412465441765687928682213723650598026143247644255856825\ | |
880 | 0067550727020875186529983636163599237979656469544571773092665671e-324" | |
881 | ); | |
882 | assert_eq!( | |
883 | to_string(f, minf64, Minus, 256, false), | |
884 | "4.940656458412465441765687928682213723650598026143247644255856825\ | |
d9579d0f AL |
885 | 0067550727020875186529983636163599237979656469544571773092665671\ |
886 | 0355939796398774796010781878126300713190311404527845817167848982\ | |
dfeec247 XL |
887 | 1036887186360569987307230500063874091535649843873124733972731696e-324" |
888 | ); | |
889 | assert_eq!( | |
890 | to_string(f, minf64, Minus, 512, false), | |
891 | "4.940656458412465441765687928682213723650598026143247644255856825\ | |
d9579d0f AL |
892 | 0067550727020875186529983636163599237979656469544571773092665671\ |
893 | 0355939796398774796010781878126300713190311404527845817167848982\ | |
894 | 1036887186360569987307230500063874091535649843873124733972731696\ | |
895 | 1514003171538539807412623856559117102665855668676818703956031062\ | |
896 | 4931945271591492455329305456544401127480129709999541931989409080\ | |
897 | 4165633245247571478690147267801593552386115501348035264934720193\ | |
dfeec247 XL |
898 | 7902681071074917033322268447533357208324319360923828934583680601e-324" |
899 | ); | |
900 | assert_eq!( | |
901 | to_string(f, minf64, Minus, 1024, false), | |
902 | "4.940656458412465441765687928682213723650598026143247644255856825\ | |
d9579d0f AL |
903 | 0067550727020875186529983636163599237979656469544571773092665671\ |
904 | 0355939796398774796010781878126300713190311404527845817167848982\ | |
905 | 1036887186360569987307230500063874091535649843873124733972731696\ | |
906 | 1514003171538539807412623856559117102665855668676818703956031062\ | |
907 | 4931945271591492455329305456544401127480129709999541931989409080\ | |
908 | 4165633245247571478690147267801593552386115501348035264934720193\ | |
909 | 7902681071074917033322268447533357208324319360923828934583680601\ | |
910 | 0601150616980975307834227731832924790498252473077637592724787465\ | |
911 | 6084778203734469699533647017972677717585125660551199131504891101\ | |
912 | 4510378627381672509558373897335989936648099411642057026370902792\ | |
913 | 4276754456522908753868250641971826553344726562500000000000000000\ | |
914 | 0000000000000000000000000000000000000000000000000000000000000000\ | |
915 | 0000000000000000000000000000000000000000000000000000000000000000\ | |
916 | 0000000000000000000000000000000000000000000000000000000000000000\ | |
dfeec247 XL |
917 | 0000000000000000000000000000000000000000000000000000000000000000e-324" |
918 | ); | |
d9579d0f AL |
919 | |
920 | // very large output | |
dfeec247 XL |
921 | assert_eq!(to_string(f, 0.0, Minus, 80000, false), format!("0.{:0>79999}e0", "")); |
922 | assert_eq!(to_string(f, 1.0e1, Minus, 80000, false), format!("1.{:0>79999}e1", "")); | |
923 | assert_eq!(to_string(f, 1.0e0, Minus, 80000, false), format!("1.{:0>79999}e0", "")); | |
924 | assert_eq!( | |
925 | to_string(f, 1.0e-1, Minus, 80000, false), | |
926 | format!( | |
927 | "1.000000000000000055511151231257827021181583404541015625{:0>79945}\ | |
928 | e-1", | |
929 | "" | |
930 | ) | |
931 | ); | |
932 | assert_eq!( | |
933 | to_string(f, 1.0e-20, Minus, 80000, false), | |
934 | format!( | |
935 | "9.999999999999999451532714542095716517295037027873924471077157760\ | |
936 | 66783064379706047475337982177734375{:0>79901}e-21", | |
937 | "" | |
938 | ) | |
939 | ); | |
d9579d0f AL |
940 | } |
941 | ||
942 | pub fn to_exact_fixed_str_test<F>(mut f_: F) | |
dfeec247 | 943 | where |
1b1a35ee | 944 | F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>], i16) -> (&'a [u8], i16), |
dfeec247 | 945 | { |
d9579d0f AL |
946 | use core::num::flt2dec::Sign::*; |
947 | ||
74b04a01 | 948 | fn to_string<T, F>(f: &mut F, v: T, sign: Sign, frac_digits: usize) -> String |
dfeec247 XL |
949 | where |
950 | T: DecodableFloat, | |
1b1a35ee | 951 | F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>], i16) -> (&'a [u8], i16), |
dfeec247 XL |
952 | { |
953 | to_string_with_parts(|buf, parts| { | |
74b04a01 | 954 | to_exact_fixed_str(|d, b, l| f(d, b, l), v, sign, frac_digits, buf, parts) |
dfeec247 | 955 | }) |
d9579d0f AL |
956 | } |
957 | ||
958 | let f = &mut f_; | |
959 | ||
74b04a01 | 960 | assert_eq!(to_string(f, 0.0, Minus, 0), "0"); |
74b04a01 | 961 | assert_eq!(to_string(f, 0.0, MinusPlus, 0), "+0"); |
cdc7bbd5 XL |
962 | assert_eq!(to_string(f, -0.0, Minus, 0), "-0"); |
963 | assert_eq!(to_string(f, -0.0, MinusPlus, 0), "-0"); | |
74b04a01 | 964 | assert_eq!(to_string(f, 0.0, Minus, 1), "0.0"); |
74b04a01 | 965 | assert_eq!(to_string(f, 0.0, MinusPlus, 1), "+0.0"); |
cdc7bbd5 XL |
966 | assert_eq!(to_string(f, -0.0, Minus, 8), "-0.00000000"); |
967 | assert_eq!(to_string(f, -0.0, MinusPlus, 8), "-0.00000000"); | |
74b04a01 XL |
968 | |
969 | assert_eq!(to_string(f, 1.0 / 0.0, Minus, 0), "inf"); | |
cdc7bbd5 XL |
970 | assert_eq!(to_string(f, 1.0 / 0.0, Minus, 1), "inf"); |
971 | assert_eq!(to_string(f, 1.0 / 0.0, MinusPlus, 64), "+inf"); | |
74b04a01 | 972 | assert_eq!(to_string(f, 0.0 / 0.0, Minus, 0), "NaN"); |
cdc7bbd5 XL |
973 | assert_eq!(to_string(f, 0.0 / 0.0, Minus, 1), "NaN"); |
974 | assert_eq!(to_string(f, 0.0 / 0.0, MinusPlus, 64), "NaN"); | |
74b04a01 | 975 | assert_eq!(to_string(f, -1.0 / 0.0, Minus, 0), "-inf"); |
cdc7bbd5 XL |
976 | assert_eq!(to_string(f, -1.0 / 0.0, Minus, 1), "-inf"); |
977 | assert_eq!(to_string(f, -1.0 / 0.0, MinusPlus, 64), "-inf"); | |
74b04a01 XL |
978 | |
979 | assert_eq!(to_string(f, 3.14, Minus, 0), "3"); | |
cdc7bbd5 | 980 | assert_eq!(to_string(f, 3.14, Minus, 0), "3"); |
74b04a01 | 981 | assert_eq!(to_string(f, 3.14, MinusPlus, 0), "+3"); |
74b04a01 | 982 | assert_eq!(to_string(f, -3.14, Minus, 0), "-3"); |
cdc7bbd5 | 983 | assert_eq!(to_string(f, -3.14, Minus, 0), "-3"); |
74b04a01 | 984 | assert_eq!(to_string(f, -3.14, MinusPlus, 0), "-3"); |
74b04a01 | 985 | assert_eq!(to_string(f, 3.14, Minus, 1), "3.1"); |
cdc7bbd5 XL |
986 | assert_eq!(to_string(f, 3.14, Minus, 2), "3.14"); |
987 | assert_eq!(to_string(f, 3.14, MinusPlus, 4), "+3.1400"); | |
988 | assert_eq!(to_string(f, -3.14, Minus, 8), "-3.14000000"); | |
74b04a01 | 989 | assert_eq!(to_string(f, -3.14, Minus, 8), "-3.14000000"); |
74b04a01 | 990 | assert_eq!(to_string(f, -3.14, MinusPlus, 8), "-3.14000000"); |
74b04a01 XL |
991 | |
992 | assert_eq!(to_string(f, 0.195, Minus, 0), "0"); | |
74b04a01 | 993 | assert_eq!(to_string(f, 0.195, MinusPlus, 0), "+0"); |
74b04a01 | 994 | assert_eq!(to_string(f, -0.195, Minus, 0), "-0"); |
cdc7bbd5 | 995 | assert_eq!(to_string(f, -0.195, Minus, 0), "-0"); |
74b04a01 | 996 | assert_eq!(to_string(f, -0.195, MinusPlus, 0), "-0"); |
74b04a01 | 997 | assert_eq!(to_string(f, 0.195, Minus, 1), "0.2"); |
cdc7bbd5 XL |
998 | assert_eq!(to_string(f, 0.195, Minus, 2), "0.20"); |
999 | assert_eq!(to_string(f, 0.195, MinusPlus, 4), "+0.1950"); | |
74b04a01 | 1000 | assert_eq!(to_string(f, -0.195, Minus, 5), "-0.19500"); |
cdc7bbd5 XL |
1001 | assert_eq!(to_string(f, -0.195, Minus, 6), "-0.195000"); |
1002 | assert_eq!(to_string(f, -0.195, MinusPlus, 8), "-0.19500000"); | |
74b04a01 XL |
1003 | |
1004 | assert_eq!(to_string(f, 999.5, Minus, 0), "1000"); | |
1005 | assert_eq!(to_string(f, 999.5, Minus, 1), "999.5"); | |
1006 | assert_eq!(to_string(f, 999.5, Minus, 2), "999.50"); | |
1007 | assert_eq!(to_string(f, 999.5, Minus, 3), "999.500"); | |
1008 | assert_eq!(to_string(f, 999.5, Minus, 30), "999.500000000000000000000000000000"); | |
1009 | ||
1010 | assert_eq!(to_string(f, 0.5, Minus, 0), "1"); | |
1011 | assert_eq!(to_string(f, 0.5, Minus, 1), "0.5"); | |
1012 | assert_eq!(to_string(f, 0.5, Minus, 2), "0.50"); | |
1013 | assert_eq!(to_string(f, 0.5, Minus, 3), "0.500"); | |
1014 | ||
1015 | assert_eq!(to_string(f, 0.95, Minus, 0), "1"); | |
1016 | assert_eq!(to_string(f, 0.95, Minus, 1), "0.9"); // because it really is less than 0.95 | |
1017 | assert_eq!(to_string(f, 0.95, Minus, 2), "0.95"); | |
1018 | assert_eq!(to_string(f, 0.95, Minus, 3), "0.950"); | |
1019 | assert_eq!(to_string(f, 0.95, Minus, 10), "0.9500000000"); | |
1020 | assert_eq!(to_string(f, 0.95, Minus, 30), "0.949999999999999955591079014994"); | |
1021 | ||
1022 | assert_eq!(to_string(f, 0.095, Minus, 0), "0"); | |
1023 | assert_eq!(to_string(f, 0.095, Minus, 1), "0.1"); | |
1024 | assert_eq!(to_string(f, 0.095, Minus, 2), "0.10"); | |
1025 | assert_eq!(to_string(f, 0.095, Minus, 3), "0.095"); | |
1026 | assert_eq!(to_string(f, 0.095, Minus, 4), "0.0950"); | |
1027 | assert_eq!(to_string(f, 0.095, Minus, 10), "0.0950000000"); | |
1028 | assert_eq!(to_string(f, 0.095, Minus, 30), "0.095000000000000001110223024625"); | |
1029 | ||
1030 | assert_eq!(to_string(f, 0.0095, Minus, 0), "0"); | |
1031 | assert_eq!(to_string(f, 0.0095, Minus, 1), "0.0"); | |
1032 | assert_eq!(to_string(f, 0.0095, Minus, 2), "0.01"); | |
1033 | assert_eq!(to_string(f, 0.0095, Minus, 3), "0.009"); // really is less than 0.0095 | |
1034 | assert_eq!(to_string(f, 0.0095, Minus, 4), "0.0095"); | |
1035 | assert_eq!(to_string(f, 0.0095, Minus, 5), "0.00950"); | |
1036 | assert_eq!(to_string(f, 0.0095, Minus, 10), "0.0095000000"); | |
1037 | assert_eq!(to_string(f, 0.0095, Minus, 30), "0.009499999999999999764077607267"); | |
1038 | ||
1039 | assert_eq!(to_string(f, 7.5e-11, Minus, 0), "0"); | |
1040 | assert_eq!(to_string(f, 7.5e-11, Minus, 3), "0.000"); | |
1041 | assert_eq!(to_string(f, 7.5e-11, Minus, 10), "0.0000000001"); | |
1042 | assert_eq!(to_string(f, 7.5e-11, Minus, 11), "0.00000000007"); // ditto | |
1043 | assert_eq!(to_string(f, 7.5e-11, Minus, 12), "0.000000000075"); | |
1044 | assert_eq!(to_string(f, 7.5e-11, Minus, 13), "0.0000000000750"); | |
1045 | assert_eq!(to_string(f, 7.5e-11, Minus, 20), "0.00000000007500000000"); | |
1046 | assert_eq!(to_string(f, 7.5e-11, Minus, 30), "0.000000000074999999999999999501"); | |
1047 | ||
1048 | assert_eq!(to_string(f, 1.0e25, Minus, 0), "10000000000000000905969664"); | |
1049 | assert_eq!(to_string(f, 1.0e25, Minus, 1), "10000000000000000905969664.0"); | |
1050 | assert_eq!(to_string(f, 1.0e25, Minus, 3), "10000000000000000905969664.000"); | |
1051 | ||
1052 | assert_eq!(to_string(f, 1.0e-6, Minus, 0), "0"); | |
1053 | assert_eq!(to_string(f, 1.0e-6, Minus, 3), "0.000"); | |
1054 | assert_eq!(to_string(f, 1.0e-6, Minus, 6), "0.000001"); | |
1055 | assert_eq!(to_string(f, 1.0e-6, Minus, 9), "0.000001000"); | |
1056 | assert_eq!(to_string(f, 1.0e-6, Minus, 12), "0.000001000000"); | |
1057 | assert_eq!(to_string(f, 1.0e-6, Minus, 22), "0.0000010000000000000000"); | |
1058 | assert_eq!(to_string(f, 1.0e-6, Minus, 23), "0.00000099999999999999995"); | |
1059 | assert_eq!(to_string(f, 1.0e-6, Minus, 24), "0.000000999999999999999955"); | |
1060 | assert_eq!(to_string(f, 1.0e-6, Minus, 25), "0.0000009999999999999999547"); | |
1061 | assert_eq!(to_string(f, 1.0e-6, Minus, 35), "0.00000099999999999999995474811182589"); | |
1062 | assert_eq!(to_string(f, 1.0e-6, Minus, 45), "0.000000999999999999999954748111825886258685614"); | |
dfeec247 | 1063 | assert_eq!( |
74b04a01 | 1064 | to_string(f, 1.0e-6, Minus, 55), |
dfeec247 XL |
1065 | "0.0000009999999999999999547481118258862586856139387236908" |
1066 | ); | |
1067 | assert_eq!( | |
74b04a01 | 1068 | to_string(f, 1.0e-6, Minus, 65), |
dfeec247 XL |
1069 | "0.00000099999999999999995474811182588625868561393872369080781936646" |
1070 | ); | |
1071 | assert_eq!( | |
74b04a01 | 1072 | to_string(f, 1.0e-6, Minus, 75), |
dfeec247 XL |
1073 | "0.000000999999999999999954748111825886258685613938723690807819366455078125000" |
1074 | ); | |
1075 | ||
74b04a01 XL |
1076 | assert_eq!(to_string(f, f32::MAX, Minus, 0), "340282346638528859811704183484516925440"); |
1077 | assert_eq!(to_string(f, f32::MAX, Minus, 1), "340282346638528859811704183484516925440.0"); | |
1078 | assert_eq!(to_string(f, f32::MAX, Minus, 2), "340282346638528859811704183484516925440.00"); | |
dfeec247 XL |
1079 | |
1080 | if cfg!(miri) { | |
1081 | // Miri is too slow | |
416331ca XL |
1082 | return; |
1083 | } | |
1084 | ||
3157f602 | 1085 | let minf32 = ldexp_f32(1.0, -149); |
74b04a01 XL |
1086 | assert_eq!(to_string(f, minf32, Minus, 0), "0"); |
1087 | assert_eq!(to_string(f, minf32, Minus, 1), "0.0"); | |
1088 | assert_eq!(to_string(f, minf32, Minus, 2), "0.00"); | |
1089 | assert_eq!(to_string(f, minf32, Minus, 4), "0.0000"); | |
1090 | assert_eq!(to_string(f, minf32, Minus, 8), "0.00000000"); | |
1091 | assert_eq!(to_string(f, minf32, Minus, 16), "0.0000000000000000"); | |
1092 | assert_eq!(to_string(f, minf32, Minus, 32), "0.00000000000000000000000000000000"); | |
dfeec247 | 1093 | assert_eq!( |
74b04a01 | 1094 | to_string(f, minf32, Minus, 64), |
dfeec247 XL |
1095 | "0.0000000000000000000000000000000000000000000014012984643248170709" |
1096 | ); | |
1097 | assert_eq!( | |
74b04a01 | 1098 | to_string(f, minf32, Minus, 128), |
dfeec247 XL |
1099 | "0.0000000000000000000000000000000000000000000014012984643248170709\ |
1100 | 2372958328991613128026194187651577175706828388979108268586060149" | |
1101 | ); | |
1102 | assert_eq!( | |
74b04a01 | 1103 | to_string(f, minf32, Minus, 256), |
dfeec247 | 1104 | "0.0000000000000000000000000000000000000000000014012984643248170709\ |
d9579d0f AL |
1105 | 2372958328991613128026194187651577175706828388979108268586060148\ |
1106 | 6638188362121582031250000000000000000000000000000000000000000000\ | |
dfeec247 XL |
1107 | 0000000000000000000000000000000000000000000000000000000000000000" |
1108 | ); | |
d9579d0f | 1109 | |
dfeec247 | 1110 | assert_eq!( |
74b04a01 | 1111 | to_string(f, f64::MAX, Minus, 0), |
dfeec247 | 1112 | "1797693134862315708145274237317043567980705675258449965989174768\ |
d9579d0f AL |
1113 | 0315726078002853876058955863276687817154045895351438246423432132\ |
1114 | 6889464182768467546703537516986049910576551282076245490090389328\ | |
1115 | 9440758685084551339423045832369032229481658085593321233482747978\ | |
dfeec247 XL |
1116 | 26204144723168738177180919299881250404026184124858368" |
1117 | ); | |
1118 | assert_eq!( | |
74b04a01 | 1119 | to_string(f, f64::MAX, Minus, 10), |
dfeec247 | 1120 | "1797693134862315708145274237317043567980705675258449965989174768\ |
d9579d0f AL |
1121 | 0315726078002853876058955863276687817154045895351438246423432132\ |
1122 | 6889464182768467546703537516986049910576551282076245490090389328\ | |
1123 | 9440758685084551339423045832369032229481658085593321233482747978\ | |
dfeec247 XL |
1124 | 26204144723168738177180919299881250404026184124858368.0000000000" |
1125 | ); | |
d9579d0f | 1126 | |
3157f602 | 1127 | let minf64 = ldexp_f64(1.0, -1074); |
74b04a01 XL |
1128 | assert_eq!(to_string(f, minf64, Minus, 0), "0"); |
1129 | assert_eq!(to_string(f, minf64, Minus, 1), "0.0"); | |
1130 | assert_eq!(to_string(f, minf64, Minus, 10), "0.0000000000"); | |
dfeec247 | 1131 | assert_eq!( |
74b04a01 | 1132 | to_string(f, minf64, Minus, 100), |
dfeec247 XL |
1133 | "0.0000000000000000000000000000000000000000000000000000000000000000\ |
1134 | 000000000000000000000000000000000000" | |
1135 | ); | |
1136 | assert_eq!( | |
74b04a01 | 1137 | to_string(f, minf64, Minus, 1000), |
dfeec247 | 1138 | "0.0000000000000000000000000000000000000000000000000000000000000000\ |
d9579d0f AL |
1139 | 0000000000000000000000000000000000000000000000000000000000000000\ |
1140 | 0000000000000000000000000000000000000000000000000000000000000000\ | |
1141 | 0000000000000000000000000000000000000000000000000000000000000000\ | |
1142 | 0000000000000000000000000000000000000000000000000000000000000000\ | |
1143 | 0004940656458412465441765687928682213723650598026143247644255856\ | |
1144 | 8250067550727020875186529983636163599237979656469544571773092665\ | |
1145 | 6710355939796398774796010781878126300713190311404527845817167848\ | |
1146 | 9821036887186360569987307230500063874091535649843873124733972731\ | |
1147 | 6961514003171538539807412623856559117102665855668676818703956031\ | |
1148 | 0624931945271591492455329305456544401127480129709999541931989409\ | |
1149 | 0804165633245247571478690147267801593552386115501348035264934720\ | |
1150 | 1937902681071074917033322268447533357208324319360923828934583680\ | |
1151 | 6010601150616980975307834227731832924790498252473077637592724787\ | |
1152 | 4656084778203734469699533647017972677717585125660551199131504891\ | |
dfeec247 XL |
1153 | 1014510378627381672509558373897335989937" |
1154 | ); | |
d9579d0f AL |
1155 | |
1156 | // very large output | |
74b04a01 XL |
1157 | assert_eq!(to_string(f, 0.0, Minus, 80000), format!("0.{:0>80000}", "")); |
1158 | assert_eq!(to_string(f, 1.0e1, Minus, 80000), format!("10.{:0>80000}", "")); | |
1159 | assert_eq!(to_string(f, 1.0e0, Minus, 80000), format!("1.{:0>80000}", "")); | |
dfeec247 | 1160 | assert_eq!( |
74b04a01 | 1161 | to_string(f, 1.0e-1, Minus, 80000), |
dfeec247 XL |
1162 | format!("0.1000000000000000055511151231257827021181583404541015625{:0>79945}", "") |
1163 | ); | |
1164 | assert_eq!( | |
74b04a01 | 1165 | to_string(f, 1.0e-20, Minus, 80000), |
dfeec247 XL |
1166 | format!( |
1167 | "0.0000000000000000000099999999999999994515327145420957165172950370\ | |
1168 | 2787392447107715776066783064379706047475337982177734375{:0>79881}", | |
1169 | "" | |
1170 | ) | |
1171 | ); | |
d9579d0f | 1172 | } |