From 55773e9d3551c37dff8f83e6b04991b6d7c3d05e Mon Sep 17 00:00:00 2001 From: Nicolas Boichat Date: Wed, 19 Mar 2025 21:29:11 +0100 Subject: [PATCH] uucore: format: num_parser: Fix large hexadecimal float parsing Large numbers can overflow u64 when doing 16u64.pow(scale): do the operation on BigInt/BigDecimal instead. Also, add a test. Wolfram Alpha can help confirm the decimal number is correct (16-16**-21). --- src/uucore/src/lib/features/format/num_parser.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/uucore/src/lib/features/format/num_parser.rs b/src/uucore/src/lib/features/format/num_parser.rs index 7cb584db1..54d60f69b 100644 --- a/src/uucore/src/lib/features/format/num_parser.rs +++ b/src/uucore/src/lib/features/format/num_parser.rs @@ -306,7 +306,8 @@ fn parse( BigDecimal::from_bigint(signed_digits, scale) } else { // Base is not 10, init at scale 0 then divide by base**scale. - BigDecimal::from_bigint(signed_digits, 0) / (base as u64).pow(scale as u32) + BigDecimal::from_bigint(signed_digits, 0) + / BigDecimal::from_bigint(BigInt::from(base as u32).pow(scale as u32), 0) }; ExtendedBigDecimal::BigDecimal(bd) }; @@ -494,6 +495,14 @@ mod tests { )), ExtendedBigDecimal::extended_parse("0x.1") ); + + // Precisely parse very large hexadecimal numbers (i.e. with a large division). + assert_eq!( + Ok(ExtendedBigDecimal::BigDecimal( + BigDecimal::from_str("15.999999999999999999999999948301211715435770320536956745627321652136743068695068359375").unwrap() + )), + ExtendedBigDecimal::extended_parse("0xf.fffffffffffffffffffff") + ); } #[test]