From 84e5ee4b861c34b373803f8a7f43b84a3d9fb3b3 Mon Sep 17 00:00:00 2001 From: Nicolas Boichat Date: Fri, 21 Mar 2025 21:25:04 +0100 Subject: [PATCH] seq: Accept underflow in parameters Also, add a test to check that a very, very, small number is treated as 0. That's probably undefined behaviour, but it does make some sense. --- src/uu/seq/src/numberparse.rs | 12 +++++++++--- tests/by-util/test_seq.rs | 12 ++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/uu/seq/src/numberparse.rs b/src/uu/seq/src/numberparse.rs index 31cc1c03e..731a43fa1 100644 --- a/src/uu/seq/src/numberparse.rs +++ b/src/uu/seq/src/numberparse.rs @@ -11,7 +11,7 @@ use std::str::FromStr; use bigdecimal::BigDecimal; use num_traits::Zero; -use uucore::format::num_parser::ExtendedParser; +use uucore::format::num_parser::{ExtendedParser, ExtendedParserError}; use crate::number::PreciseNumber; use uucore::format::ExtendedBigDecimal; @@ -61,8 +61,9 @@ fn compute_num_integral_digits(input: &str, _number: &BigDecimal) -> usize { // If there is an exponent, reparse that (yes this is not optimal, // but we can't necessarily exactly recover that from the parsed number). if parts.len() == 2 { - let exp = parts[1].parse::().unwrap(); + let exp = parts[1].parse::().unwrap_or(0); // For positive exponents, effectively expand the number. Ignore negative exponents. + // Also ignore overflowed exponents (default 0 above). if exp > 0 { digits + exp as usize } else { @@ -80,6 +81,7 @@ impl FromStr for PreciseNumber { fn from_str(input: &str) -> Result { let ebd = match ExtendedBigDecimal::extended_parse(input) { Ok(ebd) => ebd, + Err(ExtendedParserError::Underflow(ebd)) => ebd, // Treat underflow as 0 Err(_) => return Err(ParseNumberError::Float), }; @@ -95,7 +97,11 @@ impl FromStr for PreciseNumber { ExtendedBigDecimal::Nan | ExtendedBigDecimal::MinusNan => { return Err(ParseNumberError::Nan); } - ExtendedBigDecimal::BigDecimal(ref bd) => bd.clone(), + ExtendedBigDecimal::BigDecimal(ref bd) => { + // TODO: `seq` treats small numbers < 1e-4950 as 0, we could do the same + // to avoid printing senselessly small numbers. + bd.clone() + } ExtendedBigDecimal::MinusZero => BigDecimal::zero(), }; diff --git a/tests/by-util/test_seq.rs b/tests/by-util/test_seq.rs index 01ccfc11f..b112c75d8 100644 --- a/tests/by-util/test_seq.rs +++ b/tests/by-util/test_seq.rs @@ -911,6 +911,18 @@ fn test_parse_out_of_bounds_exponents() { .args(&["1e-9223372036854775808"]) .succeeds() .stdout_only(""); + + // GNU seq supports arbitrarily small exponents (and treats the value as 0). + new_ucmd!() + .args(&["1e-922337203685477580800000000", "1"]) + .succeeds() + .stdout_only("0\n1\n"); + + // Check we can also underflow to -0.0. + new_ucmd!() + .args(&["-1e-922337203685477580800000000", "1"]) + .succeeds() + .stdout_only("-0\n1\n"); } #[ignore]