From 4f7a02affc4a7803fb5b471ca59a723890004fb6 Mon Sep 17 00:00:00 2001 From: Alexander Shirokov Date: Sat, 4 Jan 2025 18:12:04 +0100 Subject: [PATCH] seq:simplify detect_precision --- src/uu/seq/src/floatparse.rs | 81 +++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 33 deletions(-) diff --git a/src/uu/seq/src/floatparse.rs b/src/uu/seq/src/floatparse.rs index 591ccc5fae8..c00b6126b1f 100644 --- a/src/uu/seq/src/floatparse.rs +++ b/src/uu/seq/src/floatparse.rs @@ -81,45 +81,47 @@ pub fn parse_hexadecimal_float(s: &str) -> Result Option { - let mut precision: Option = None; - let decimal_point_index = s.find('.'); let hex_index = s.find(['x', 'X']); - let power_index = s.find(['p', 'P']); - if decimal_point_index.is_none() && power_index.is_none() { - precision = Some(0); + let point_index = s.find('.'); + + if hex_index.is_some() { + // Hex value. Returns: + // - 0 for a hexadecimal integer (filled above) + // - None for a hexadecimal floating-point number (the default value of precision) + let power_index = s.find(['p', 'P']); + if point_index.is_none() && power_index.is_none() { + // No decimal point and no 'p' (power) => integer => precision = 0 + return Some(0); + } else { + return None; + } } - if hex_index.is_none() { - let fractional_length = if let Some(decimal) = decimal_point_index { - s[decimal..] - .chars() - .skip(1) - .take_while(|x| x.is_ascii_digit()) - .count() + // This is a decimal floating point. The precision depends on two parameters: + // - the number of fractional digits + // - the exponent + // Let's detect the number of fractional digits + let fractional_length = if let Some(point_index) = point_index { + s[point_index + 1..] + .chars() + .take_while(|c| c.is_ascii_digit()) + .count() + } else { + 0 + }; + + let mut precision = Some(fractional_length); + + // Let's update the precision if exponent is present + if let Some(exponent_index) = s.find(['e', 'E']) { + let exponent_value: i32 = s[exponent_index + 1..].parse().unwrap_or(0); + if exponent_value < 0 { + precision = precision.map(|p| p + exponent_value.unsigned_abs() as usize); } else { - 0 - }; - - precision = Some(fractional_length as i32); - - if let Some(exponent) = s.find(['e', 'E']) { - let length = s[exponent..] - .chars() - .skip(1) - .take_while(|x| x.is_ascii_digit() || *x == '-' || *x == '+') - .count(); - - if length > 0 { - let exponent_value: i32 = s[exponent + 1..=exponent + length].parse().unwrap_or(0); - if exponent_value < 0 { - precision = precision.map(|x| x + exponent_value.abs()); - } else { - precision = precision.map(|x| x - x.min(exponent_value)); - } - } + precision = precision.map(|p| p - p.min(exponent_value as usize)); } } - precision.map(|x| x as usize) + precision } /// Parse the sign multiplier. @@ -372,6 +374,7 @@ mod tests { assert_eq!(precise_num.num_integral_digits, 4); assert_eq!(precise_num.num_fractional_digits, 1); } + #[test] fn test_detect_precision() { assert_eq!(detect_precision("1"), Some(0)); @@ -383,7 +386,19 @@ mod tests { assert_eq!(detect_precision("1.1"), Some(1)); assert_eq!(detect_precision("1.12"), Some(2)); assert_eq!(detect_precision("1.12345678"), Some(8)); + assert_eq!(detect_precision("1.12345678e-3"), Some(11)); assert_eq!(detect_precision("1.1e-1"), Some(2)); assert_eq!(detect_precision("1.1e-3"), Some(4)); } + + #[test] + fn test_detect_precision_invalid() { + // Just to make sure it's not crash on incomplete values/bad format + // Good enough for now. + assert_eq!(detect_precision("1."), Some(0)); + assert_eq!(detect_precision("1e"), Some(0)); + assert_eq!(detect_precision("1e-"), Some(0)); + assert_eq!(detect_precision("1e+"), Some(0)); + assert_eq!(detect_precision("1em"), Some(0)); + } }