1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-30 04:27:45 +00:00

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).
This commit is contained in:
Nicolas Boichat 2025-03-19 21:29:11 +01:00
parent b5a658528b
commit 55773e9d35

View file

@ -306,7 +306,8 @@ fn parse(
BigDecimal::from_bigint(signed_digits, scale) BigDecimal::from_bigint(signed_digits, scale)
} else { } else {
// Base is not 10, init at scale 0 then divide by base**scale. // 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) ExtendedBigDecimal::BigDecimal(bd)
}; };
@ -494,6 +495,14 @@ mod tests {
)), )),
ExtendedBigDecimal::extended_parse("0x.1") 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] #[test]