mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 03:27:44 +00:00
seq: use BigDecimal to represent floats (#2698)
* seq: use BigDecimal to represent floats Use `BigDecimal` to represent arbitrary precision floats in order to prevent numerical precision issues when iterating over a sequence of numbers. This commit makes several changes at once to accomplish this goal. First, it creates a new struct, `PreciseNumber`, that is responsible for storing not only the number itself but also the number of digits (both integer and decimal) needed to display it. This information is collected at the time of parsing the number, which lives in the new `numberparse.rs` module. Second, it uses the `BigDecimal` struct to store arbitrary precision floating point numbers instead of the previous `f64` primitive type. This protects against issues of numerical precision when repeatedly accumulating a very small increment. Third, since neither the `BigDecimal` nor `BigInt` types have a representation of infinity, minus infinity, minus zero, or NaN, we add the `ExtendedBigDecimal` and `ExtendedBigInt` enumerations which extend the basic types with these concepts. * fixup! seq: use BigDecimal to represent floats * fixup! seq: use BigDecimal to represent floats * fixup! seq: use BigDecimal to represent floats * fixup! seq: use BigDecimal to represent floats * fixup! seq: use BigDecimal to represent floats
This commit is contained in:
parent
a7aa6b8e3a
commit
2e12316ae1
10 changed files with 1471 additions and 425 deletions
|
@ -7,25 +7,25 @@ fn test_hex_rejects_sign_after_identifier() {
|
|||
.args(&["0x-123ABC"])
|
||||
.fails()
|
||||
.no_stdout()
|
||||
.stderr_contains("invalid hexadecimal argument: '0x-123ABC'")
|
||||
.stderr_contains("invalid floating point argument: '0x-123ABC'")
|
||||
.stderr_contains("for more information.");
|
||||
new_ucmd!()
|
||||
.args(&["0x+123ABC"])
|
||||
.fails()
|
||||
.no_stdout()
|
||||
.stderr_contains("invalid hexadecimal argument: '0x+123ABC'")
|
||||
.stderr_contains("invalid floating point argument: '0x+123ABC'")
|
||||
.stderr_contains("for more information.");
|
||||
new_ucmd!()
|
||||
.args(&["-0x-123ABC"])
|
||||
.fails()
|
||||
.no_stdout()
|
||||
.stderr_contains("invalid hexadecimal argument: '-0x-123ABC'")
|
||||
.stderr_contains("invalid floating point argument: '-0x-123ABC'")
|
||||
.stderr_contains("for more information.");
|
||||
new_ucmd!()
|
||||
.args(&["-0x+123ABC"])
|
||||
.fails()
|
||||
.no_stdout()
|
||||
.stderr_contains("invalid hexadecimal argument: '-0x+123ABC'")
|
||||
.stderr_contains("invalid floating point argument: '-0x+123ABC'")
|
||||
.stderr_contains("for more information.");
|
||||
}
|
||||
|
||||
|
@ -60,7 +60,7 @@ fn test_hex_identifier_in_wrong_place() {
|
|||
.args(&["1234ABCD0x"])
|
||||
.fails()
|
||||
.no_stdout()
|
||||
.stderr_contains("invalid hexadecimal argument: '1234ABCD0x'")
|
||||
.stderr_contains("invalid floating point argument: '1234ABCD0x'")
|
||||
.stderr_contains("for more information.");
|
||||
}
|
||||
|
||||
|
@ -479,6 +479,15 @@ fn test_width_decimal_scientific_notation_trailing_zeros_increment() {
|
|||
.no_stderr();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_width_negative_scientific_notation() {
|
||||
new_ucmd!()
|
||||
.args(&["-w", "-1e-3", "1"])
|
||||
.succeeds()
|
||||
.stdout_is("-0.001\n00.999\n")
|
||||
.no_stderr();
|
||||
}
|
||||
|
||||
/// Test that trailing zeros in the end argument do not contribute to width.
|
||||
#[test]
|
||||
fn test_width_decimal_scientific_notation_trailing_zeros_end() {
|
||||
|
@ -544,3 +553,63 @@ fn test_trailing_whitespace_error() {
|
|||
// --help' for more information."
|
||||
.stderr_contains("for more information.");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_negative_zero_int_start_float_increment() {
|
||||
new_ucmd!()
|
||||
.args(&["-0", "0.1", "0.1"])
|
||||
.succeeds()
|
||||
.stdout_is("-0.0\n0.1\n")
|
||||
.no_stderr();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_float_precision_increment() {
|
||||
new_ucmd!()
|
||||
.args(&["999", "0.1", "1000.1"])
|
||||
.succeeds()
|
||||
.stdout_is(
|
||||
"999.0
|
||||
999.1
|
||||
999.2
|
||||
999.3
|
||||
999.4
|
||||
999.5
|
||||
999.6
|
||||
999.7
|
||||
999.8
|
||||
999.9
|
||||
1000.0
|
||||
1000.1
|
||||
",
|
||||
)
|
||||
.no_stderr();
|
||||
}
|
||||
|
||||
/// Test for floating point precision issues.
|
||||
#[test]
|
||||
fn test_negative_increment_decimal() {
|
||||
new_ucmd!()
|
||||
.args(&["0.1", "-0.1", "-0.2"])
|
||||
.succeeds()
|
||||
.stdout_is("0.1\n0.0\n-0.1\n-0.2\n")
|
||||
.no_stderr();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_zero_not_first() {
|
||||
new_ucmd!()
|
||||
.args(&["-w", "-0.1", "0.1", "0.1"])
|
||||
.succeeds()
|
||||
.stdout_is("-0.1\n00.0\n00.1\n")
|
||||
.no_stderr();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rounding_end() {
|
||||
new_ucmd!()
|
||||
.args(&["1", "-1", "0.1"])
|
||||
.succeeds()
|
||||
.stdout_is("1\n")
|
||||
.no_stderr();
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue