From 30bfaafc0534287f70af9c6980fc8d14df0c7c60 Mon Sep 17 00:00:00 2001 From: Finn Bear Date: Wed, 18 Sep 2024 08:48:58 -0700 Subject: [PATCH 1/4] Fix f64 dec limit edge case. --- src/decimal.rs | 3 +++ tests/decimal_tests.rs | 13 +++++++++++++ 2 files changed, 16 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..86df3fb 100644 --- a/tests/decimal_tests.rs +++ b/tests/decimal_tests.rs @@ -3136,6 +3136,19 @@ 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; + + let max_next_up_next_up = 79228162514264355185729994752f64; + let max_next_up = 79228162514264337593543950336f64; + let max = 79228162514264328797450928128f64; + + assert!(Decimal::from_f64(max_next_up_next_up).is_none(), "from_f64(79228162514264355185729994752f64)"); + assert!(Decimal::from_f64(max_next_up).is_none(), "from_f64(79228162514264337593543950336f64)"); + assert_eq!("79228162514264328797450928128", Decimal::from_f64(max).unwrap().to_string(), "from_f64(79228162514264328797450928128f64)"); +} + #[test] fn it_converts_from_f64_retaining_bits() { let tests = [ From d0c045f3a829d8f14c3893b5044bb97a0484251f Mon Sep 17 00:00:00 2001 From: Finn Bear Date: Wed, 18 Sep 2024 08:49:08 -0700 Subject: [PATCH 2/4] fmt. --- tests/decimal_tests.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/tests/decimal_tests.rs b/tests/decimal_tests.rs index 86df3fb..619bc65 100644 --- a/tests/decimal_tests.rs +++ b/tests/decimal_tests.rs @@ -3144,9 +3144,19 @@ fn it_converts_from_f64_dec_limits() { let max_next_up = 79228162514264337593543950336f64; let max = 79228162514264328797450928128f64; - assert!(Decimal::from_f64(max_next_up_next_up).is_none(), "from_f64(79228162514264355185729994752f64)"); - assert!(Decimal::from_f64(max_next_up).is_none(), "from_f64(79228162514264337593543950336f64)"); - assert_eq!("79228162514264328797450928128", Decimal::from_f64(max).unwrap().to_string(), "from_f64(79228162514264328797450928128f64)"); + assert!( + Decimal::from_f64(max_next_up_next_up).is_none(), + "from_f64(79228162514264355185729994752f64)" + ); + assert!( + Decimal::from_f64(max_next_up).is_none(), + "from_f64(79228162514264337593543950336f64)" + ); + assert_eq!( + "79228162514264328797450928128", + Decimal::from_f64(max).unwrap().to_string(), + "from_f64(79228162514264328797450928128f64)" + ); } #[test] From 7f43a03297e1433fa3c05aa85fd053fff28f19e6 Mon Sep 17 00:00:00 2001 From: Paul Mason Date: Wed, 18 Sep 2024 14:51:00 -0700 Subject: [PATCH 3/4] Minor formatting for test clarification --- tests/decimal_tests.rs | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/tests/decimal_tests.rs b/tests/decimal_tests.rs index 619bc65..a12937e 100644 --- a/tests/decimal_tests.rs +++ b/tests/decimal_tests.rs @@ -3140,22 +3140,29 @@ fn it_converts_from_f64_limits() { fn it_converts_from_f64_dec_limits() { use num_traits::FromPrimitive; - let max_next_up_next_up = 79228162514264355185729994752f64; - let max_next_up = 79228162514264337593543950336f64; - let max = 79228162514264328797450928128f64; + // 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; + let max = 79_228_162_514_264_337_593_543_950_335_f64; assert!( - Decimal::from_f64(max_next_up_next_up).is_none(), - "from_f64(79228162514264355185729994752f64)" + 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_next_up).is_none(), - "from_f64(79228162514264337593543950336f64)" + 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)" + ); + assert_eq!( + "79228162514264337593543950335", Decimal::from_f64(max).unwrap().to_string(), - "from_f64(79228162514264328797450928128f64)" + "from_f64(79_228_162_514_264_337_593_543_950_335_f64) -> some (at max)" ); } From 76d540bcdefef553ee1b7e1949355e44273bb49c Mon Sep 17 00:00:00 2001 From: Paul Mason Date: Wed, 18 Sep 2024 14:55:03 -0700 Subject: [PATCH 4/4] Remove max test --- tests/decimal_tests.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/decimal_tests.rs b/tests/decimal_tests.rs index a12937e..a22e09b 100644 --- a/tests/decimal_tests.rs +++ b/tests/decimal_tests.rs @@ -3144,7 +3144,6 @@ fn it_converts_from_f64_dec_limits() { 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; - let max = 79_228_162_514_264_337_593_543_950_335_f64; assert!( Decimal::from_f64(over_max).is_none(), @@ -3159,11 +3158,6 @@ fn it_converts_from_f64_dec_limits() { Decimal::from_f64(under_max).unwrap().to_string(), "from_f64(79_228_162_514_264_328_797_450_928_128_f64) -> some (inside limits)" ); - assert_eq!( - "79228162514264337593543950335", - Decimal::from_f64(max).unwrap().to_string(), - "from_f64(79_228_162_514_264_337_593_543_950_335_f64) -> some (at max)" - ); } #[test]