Fix negative precision round with ints (issue #9049) (#9073)

# Description
Before this PR, `math round` ignores the input if it's an `int`. This
results in the following behaviour:
```
> 123 | math round --precision -1
123
```
When the correct result is 120.

Now `int values` are converted to `float values` before actually
rounding up the number in order to take advantage of the float
implementation.

Fixes #9049.
This commit is contained in:
juanPabloMiceli 2023-05-03 18:07:32 -03:00 committed by GitHub
parent 5fcbefb7b4
commit 7fb48b9a2f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 45 additions and 9 deletions

View File

@ -75,11 +75,33 @@ impl Command for SubCommand {
span: Span::test_data(), span: Span::test_data(),
}), }),
}, },
Example {
description: "Apply negative precision to a list of numbers",
example: "[123, 123.3, -123.4] | math round -p -1",
result: Some(Value::List {
vals: vec![
Value::test_int(120),
Value::test_int(120),
Value::test_int(-120),
],
span: Span::test_data(),
}),
},
] ]
} }
} }
fn operate(value: Value, head: Span, precision: Option<i64>) -> Value { fn operate(value: Value, head: Span, precision: Option<i64>) -> Value {
// We treat int values as float values in order to avoid code repetition in the match closure
let value = if let Value::Int { val, span } = value {
Value::Float {
val: val as f64,
span,
}
} else {
value
};
match value { match value {
Value::Float { val, span } => match precision { Value::Float { val, span } => match precision {
Some(precision_number) => Value::Float { Some(precision_number) => Value::Float {
@ -92,7 +114,6 @@ fn operate(value: Value, head: Span, precision: Option<i64>) -> Value {
span, span,
}, },
}, },
Value::Int { .. } => value,
Value::Error { .. } => value, Value::Error { .. } => value,
other => Value::Error { other => Value::Error {
error: Box::new(ShellError::OnlySupportsThisInputType { error: Box::new(ShellError::OnlySupportsThisInputType {

View File

@ -2,20 +2,35 @@ use nu_test_support::nu;
#[test] #[test]
fn can_round_very_large_numbers() { fn can_round_very_large_numbers() {
let actual = nu!( let actual = nu!("18.1372544780074142289927665486772012345 | math round");
cwd: ".",
"echo 18.1372544780074142289927665486772012345 | math round"
);
assert_eq!(actual.out, "18") assert_eq!(actual.out, "18")
} }
#[test] #[test]
fn can_round_very_large_numbers_with_precision() { fn can_round_very_large_numbers_with_precision() {
let actual = nu!( let actual = nu!("18.13725447800741422899276654867720121457878988 | math round -p 10");
cwd: ".",
"echo 18.13725447800741422899276654867720121457878988 | math round -p 10"
);
assert_eq!(actual.out, "18.137254478") assert_eq!(actual.out, "18.137254478")
} }
#[test]
fn can_round_integer_with_negative_precision() {
let actual = nu!("123 | math round -p -1");
assert_eq!(actual.out, "120")
}
#[test]
fn can_round_float_with_negative_precision() {
let actual = nu!("123.3 | math round -p -1");
assert_eq!(actual.out, "120")
}
#[test]
fn fails_with_wrong_input_type() {
let actual = nu!("\"not_a_number\" | math round");
assert!(actual.err.contains("Input type not supported"))
}