Skip to content

Commit 5c13284

Browse files
committed
seq: Parse integral and fractional number of digits in the same function
A lot of the code can be shared, and parsing is quite straightforward as we know that the digit is somewhat valid.
1 parent da54c96 commit 5c13284

File tree

3 files changed

+57
-251
lines changed

3 files changed

+57
-251
lines changed

src/uu/seq/src/hexadecimalfloat.rs

Lines changed: 0 additions & 206 deletions
This file was deleted.

src/uu/seq/src/numberparse.rs

Lines changed: 57 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,9 @@
99
//! [`PreciseNumber`] struct.
1010
use std::str::FromStr;
1111

12-
use bigdecimal::BigDecimal;
13-
use num_traits::Zero;
1412
use uucore::format::num_parser::{ExtendedParser, ExtendedParserError};
1513

16-
use crate::{hexadecimalfloat, number::PreciseNumber};
14+
use crate::number::PreciseNumber;
1715
use uucore::format::ExtendedBigDecimal;
1816

1917
/// An error returned when parsing a number fails.
@@ -23,10 +21,11 @@ pub enum ParseNumberError {
2321
Nan,
2422
}
2523

26-
// Compute the number of integral digits in input string. We know that the
27-
// string has already been parsed correctly, so we don't need to be too
28-
// careful.
29-
fn compute_num_integral_digits(input: &str, _number: &BigDecimal) -> usize {
24+
// Compute the number of integral and fractional digits in input string,
25+
// and wrap the result in a PreciseNumber.
26+
// We know that the string has already been parsed correctly, so we don't
27+
// need to be too careful.
28+
fn compute_num_digits(input: &str, ebd: ExtendedBigDecimal) -> PreciseNumber {
3029
let input = input.to_lowercase();
3130
let mut input = input.trim_start();
3231

@@ -35,42 +34,63 @@ fn compute_num_integral_digits(input: &str, _number: &BigDecimal) -> usize {
3534
input = trimmed;
3635
}
3736

38-
// Integral digits for an hex number is ill-defined.
37+
// Integral digits for any hex number is ill-defined (0 is fine as an output)
38+
// Fractional digits for an floating hex number is ill-defined, return None
39+
// as we'll totally ignore that number for precision computations.
40+
// Still return 0 for hex integers though.
3941
if input.starts_with("0x") || input.starts_with("-0x") {
40-
return 0;
42+
return PreciseNumber {
43+
number: ebd,
44+
num_integral_digits: 0,
45+
num_fractional_digits: if input.contains(".") || input.contains("p") {
46+
None
47+
} else {
48+
Some(0)
49+
},
50+
};
4151
}
4252

4353
// Split the exponent part, if any
4454
let parts: Vec<&str> = input.split("e").collect();
4555
debug_assert!(parts.len() <= 2);
4656

4757
// Count all the digits up to `.`, `-` sign is included.
48-
let digits: usize = match parts[0].find(".") {
58+
let (mut int_digits, mut frac_digits) = match parts[0].find(".") {
4959
Some(i) => {
5060
// Cover special case .X and -.X where we behave as if there was a leading 0:
5161
// 0.X, -0.X.
52-
match i {
62+
let int_digits = match i {
5363
0 => 1,
5464
1 if parts[0].starts_with("-") => 2,
5565
_ => i,
56-
}
66+
};
67+
68+
(int_digits, parts[0].len() - i - 1)
5769
}
58-
None => parts[0].len(),
70+
None => (parts[0].len(), 0),
5971
};
6072

6173
// If there is an exponent, reparse that (yes this is not optimal,
6274
// but we can't necessarily exactly recover that from the parsed number).
6375
if parts.len() == 2 {
6476
let exp = parts[1].parse::<i64>().unwrap_or(0);
6577
// For positive exponents, effectively expand the number. Ignore negative exponents.
66-
// Also ignore overflowed exponents (default 0 above).
78+
// Also ignore overflowed exponents (unwrap_or(0)).
6779
if exp > 0 {
68-
digits + exp as usize
80+
int_digits += exp.try_into().unwrap_or(0)
81+
};
82+
frac_digits = if exp < frac_digits as i64 {
83+
// Subtract from i128 to avoid any overflow
84+
(frac_digits as i128 - exp as i128).try_into().unwrap_or(0)
6985
} else {
70-
digits
86+
0
7187
}
72-
} else {
73-
digits
88+
}
89+
90+
PreciseNumber {
91+
number: ebd,
92+
num_integral_digits: int_digits,
93+
num_fractional_digits: Some(frac_digits),
7494
}
7595
}
7696

@@ -80,36 +100,29 @@ impl FromStr for PreciseNumber {
80100
type Err = ParseNumberError;
81101
fn from_str(input: &str) -> Result<Self, Self::Err> {
82102
let ebd = match ExtendedBigDecimal::extended_parse(input) {
83-
Ok(ebd) => ebd,
103+
Ok(ebd) => match ebd {
104+
// Handle special values
105+
ExtendedBigDecimal::BigDecimal(_) | ExtendedBigDecimal::MinusZero => {
106+
// TODO: GNU `seq` treats small numbers < 1e-4950 as 0, we could do the same
107+
// to avoid printing senselessly small numbers.
108+
ebd
109+
}
110+
ExtendedBigDecimal::Infinity | ExtendedBigDecimal::MinusInfinity => {
111+
return Ok(PreciseNumber {
112+
number: ebd,
113+
num_integral_digits: 0,
114+
num_fractional_digits: Some(0),
115+
});
116+
}
117+
ExtendedBigDecimal::Nan | ExtendedBigDecimal::MinusNan => {
118+
return Err(ParseNumberError::Nan);
119+
}
120+
},
84121
Err(ExtendedParserError::Underflow(ebd)) => ebd, // Treat underflow as 0
85122
Err(_) => return Err(ParseNumberError::Float),
86123
};
87124

88-
// Handle special values, get a BigDecimal to help digit-counting.
89-
let bd = match ebd {
90-
ExtendedBigDecimal::Infinity | ExtendedBigDecimal::MinusInfinity => {
91-
return Ok(PreciseNumber {
92-
number: ebd,
93-
num_integral_digits: 0,
94-
num_fractional_digits: Some(0),
95-
});
96-
}
97-
ExtendedBigDecimal::Nan | ExtendedBigDecimal::MinusNan => {
98-
return Err(ParseNumberError::Nan);
99-
}
100-
ExtendedBigDecimal::BigDecimal(ref bd) => {
101-
// TODO: `seq` treats small numbers < 1e-4950 as 0, we could do the same
102-
// to avoid printing senselessly small numbers.
103-
bd.clone()
104-
}
105-
ExtendedBigDecimal::MinusZero => BigDecimal::zero(),
106-
};
107-
108-
Ok(PreciseNumber {
109-
number: ebd,
110-
num_integral_digits: compute_num_integral_digits(input, &bd),
111-
num_fractional_digits: hexadecimalfloat::parse_precision(input),
112-
})
125+
Ok(compute_num_digits(input, ebd))
113126
}
114127
}
115128

src/uu/seq/src/seq.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ use uucore::format::{ExtendedBigDecimal, Format, num_format};
1515
use uucore::{format_usage, help_about, help_usage};
1616

1717
mod error;
18-
mod hexadecimalfloat;
1918

2019
// public to allow fuzzing
2120
#[cfg(fuzzing)]

0 commit comments

Comments
 (0)