From ca982d6603b849d1e9e0fe20e1ace7afd37cbc84 Mon Sep 17 00:00:00 2001 From: Finn Bear Date: Wed, 18 Sep 2024 14:59:23 -0700 Subject: [PATCH] Fix `f64` dec limit edge case (#678) --- Co-authored-by: Paul Mason --- src/decimal.rs | 3 +++ tests/decimal_tests.rs | 24 ++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/decimal.rs b/src/decimal.rs index 3a1d787..5df67f3 100644 --- a/src/decimal.rs +++ b/src/decimal.rs @@ -2190,6 +2190,9 @@ fn base2_to_decimal( exponent10 -= 1; exponent5 += 1; ops::array::shl1_internal(bits, 0); + } else if exponent10 * 2 > -exponent5 { + // Multiplying by >=2 which, due to the previous condition, means an overflow. + return None; } else { // The mantissa would overflow if shifted. Therefore it should be // directly divided by 5. This will lose significant digits, unless diff --git a/tests/decimal_tests.rs b/tests/decimal_tests.rs index 8bac1cd..a22e09b 100644 --- a/tests/decimal_tests.rs +++ b/tests/decimal_tests.rs @@ -3136,6 +3136,30 @@ fn it_converts_from_f64_limits() { assert!(Decimal::try_from(f64::MIN).is_err(), "try_from(f64::MAX)"); } +#[test] +fn it_converts_from_f64_dec_limits() { + use num_traits::FromPrimitive; + + // Note Decimal MAX is: 79_228_162_514_264_337_593_543_950_335 + let over_max = 79_228_162_514_264_355_185_729_994_752_f64; + let max_plus_one = 79_228_162_514_264_337_593_543_950_336_f64; + let under_max = 79_228_162_514_264_328_797_450_928_128_f64; + + assert!( + Decimal::from_f64(over_max).is_none(), + "from_f64(79_228_162_514_264_355_185_729_994_752_f64) -> none (too large)" + ); + assert!( + Decimal::from_f64(max_plus_one).is_none(), + "from_f64(79_228_162_514_264_337_593_543_950_336_f64) -> none (too large)" + ); + assert_eq!( + "79228162514264328797450928128", + Decimal::from_f64(under_max).unwrap().to_string(), + "from_f64(79_228_162_514_264_328_797_450_928_128_f64) -> some (inside limits)" + ); +} + #[test] fn it_converts_from_f64_retaining_bits() { let tests = [