diff options
| author | Kang Seonghoon <public+git@mearie.org> | 2015-04-21 20:32:25 +0900 |
|---|---|---|
| committer | Kang Seonghoon <public+git@mearie.org> | 2015-05-06 14:22:26 +0900 |
| commit | 97ea7c14bae496d6444752be570dd41cf1a507bd (patch) | |
| tree | 0a0b52c4568cf5ccd53faa2f8662cc6c37b2adc4 /src | |
| parent | 8a195f075417ad78084ef2e1c5e294ac35d6cafa (diff) | |
| download | rust-97ea7c14bae496d6444752be570dd41cf1a507bd.tar.gz rust-97ea7c14bae496d6444752be570dd41cf1a507bd.zip | |
core: fixed a slight bug.
The bug involves the incorrect logic for `core::num::flt2dec::decoder`. This makes some numbers in the form of 2^n missing one final digits, which breaks the bijectivity criterion. The regression tests have been added, and f32 exhaustive test is rerun to get the updated result.
Diffstat (limited to 'src')
| -rw-r--r-- | src/libcore/num/flt2dec/decoder.rs | 12 | ||||
| -rw-r--r-- | src/libcoretest/num/flt2dec/mod.rs | 18 | ||||
| -rw-r--r-- | src/libcoretest/num/flt2dec/strategy/grisu.rs | 2 |
3 files changed, 23 insertions, 9 deletions
diff --git a/src/libcore/num/flt2dec/decoder.rs b/src/libcore/num/flt2dec/decoder.rs index 4b7d00f80e1..d4473e6bc0c 100644 --- a/src/libcore/num/flt2dec/decoder.rs +++ b/src/libcore/num/flt2dec/decoder.rs @@ -75,7 +75,7 @@ pub fn decode<T: DecodableFloat>(v: T) -> (/*negative?*/ bool, FullDecoded) { FpCategory::Infinite => FullDecoded::Infinite, FpCategory::Zero => FullDecoded::Zero, FpCategory::Subnormal => { - // (mant - 2, exp) -- (mant, exp) -- (mant + 2, exp) + // neighbors: (mant - 2, exp) -- (mant, exp) -- (mant + 2, exp) // Float::integer_decode always preserves the exponent, // so the mantissa is scaled for subnormals. FullDecoded::Finite(Decoded { mant: mant, minus: 1, plus: 1, @@ -83,13 +83,13 @@ pub fn decode<T: DecodableFloat>(v: T) -> (/*negative?*/ bool, FullDecoded) { } FpCategory::Normal => { let minnorm = <T as DecodableFloat>::min_pos_norm_value().integer_decode(); - if mant == minnorm.0 && exp == minnorm.1 { - // (maxmant, exp - 1) -- (minnormmant, exp) -- (minnormmant + 1, exp) + if mant == minnorm.0 { + // neighbors: (maxmant, exp - 1) -- (minnormmant, exp) -- (minnormmant + 1, exp) // where maxmant = minnormmant * 2 - 1 - FullDecoded::Finite(Decoded { mant: mant << 1, minus: 1, plus: 2, - exp: exp - 1, inclusive: even }) + FullDecoded::Finite(Decoded { mant: mant << 2, minus: 1, plus: 2, + exp: exp - 2, inclusive: even }) } else { - // (mant - 1, exp) -- (mant, exp) -- (mant + 1, exp) + // neighbors: (mant - 1, exp) -- (mant, exp) -- (mant + 1, exp) FullDecoded::Finite(Decoded { mant: mant << 1, minus: 1, plus: 1, exp: exp - 1, inclusive: even }) } diff --git a/src/libcoretest/num/flt2dec/mod.rs b/src/libcoretest/num/flt2dec/mod.rs index 3ffec7c007e..95f9eeec2c8 100644 --- a/src/libcoretest/num/flt2dec/mod.rs +++ b/src/libcoretest/num/flt2dec/mod.rs @@ -216,6 +216,13 @@ pub fn f32_shortest_sanity_test<F>(mut f: F) where F: FnMut(&Decoded, &mut [u8]) // 10^18 * 0.314159231156617216 check_shortest!(f(3.141592e17f32) => b"3141592", 18); + // regression test for decoders + // 10^8 * 0.3355443 + // 10^8 * 0.33554432 + // 10^8 * 0.33554436 + let twoto25: f32 = StdFloat::ldexp(1.0, 25); + check_shortest!(f(twoto25) => b"33554432", 8); + // 10^39 * 0.340282326356119256160033759537265639424 // 10^39 * 0.34028234663852885981170418348451692544 // 10^39 * 0.340282366920938463463374607431768211456 @@ -308,6 +315,13 @@ pub fn f64_shortest_sanity_test<F>(mut f: F) where F: FnMut(&Decoded, &mut [u8]) // 10^18 * 0.314159200000000064 check_shortest!(f(3.141592e17f64) => b"3141592", 18); + // regression test for decoders + // 10^20 * 0.18446744073709549568 + // 10^20 * 0.18446744073709551616 + // 10^20 * 0.18446744073709555712 + let twoto64: f64 = StdFloat::ldexp(1.0, 64); + check_shortest!(f(twoto64) => b"18446744073709552", 20); + // pathological case: high = 10^23 (exact). tie breaking should always prefer that. // 10^24 * 0.099999999999999974834176 // 10^24 * 0.099999999999999991611392 @@ -492,7 +506,7 @@ pub fn f32_exhaustive_equivalence_test<F, G>(f: F, g: G, k: usize) // so why not simply testing all of them? // // this is of course very stressful (and thus should be behind an `#[ignore]` attribute), - // but with `-O3 -C lto` this only takes about two hours or so. + // but with `-C opt-level=3 -C lto` this only takes about an hour or so. // iterate from 0x0000_0001 to 0x7f7f_ffff, i.e. all finite ranges let (npassed, nignored) = iterate("f32_exhaustive_equivalence_test", @@ -500,7 +514,7 @@ pub fn f32_exhaustive_equivalence_test<F, G>(f: F, g: G, k: usize) let x: f32 = unsafe {mem::transmute(i as u32 + 1)}; decode_finite(x) }); - assert_eq!((npassed, nignored), (2121451879, 17643160)); + assert_eq!((npassed, nignored), (2121451881, 17643158)); } fn to_string_with_parts<F>(mut f: F) -> String diff --git a/src/libcoretest/num/flt2dec/strategy/grisu.rs b/src/libcoretest/num/flt2dec/strategy/grisu.rs index 3d798c8726c..e5b8a9dcc38 100644 --- a/src/libcoretest/num/flt2dec/strategy/grisu.rs +++ b/src/libcoretest/num/flt2dec/strategy/grisu.rs @@ -60,7 +60,7 @@ fn shortest_f32_exhaustive_equivalence_test() { // // this reports the progress and the number of f32 values returned `None`. // with `--nocapture` (and plenty of time and appropriate rustc flags), this should print: - // `done, ignored=17643160 passed=2121451879 failed=0`. + // `done, ignored=17643158 passed=2121451881 failed=0`. use core::num::flt2dec::strategy::dragon::format_shortest as fallback; f32_exhaustive_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS); |
