-
Notifications
You must be signed in to change notification settings - Fork 0
8700: fix: liberal parsing of zero scale decimals #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -963,6 +963,14 @@ pub fn parse_decimal<T: DecimalType>( | |
| } | ||
|
|
||
| if !is_e_notation { | ||
| if scale == 0 && fractionals > 0 { | ||
| // The input string contained some fractional digits after the decimal point despite | ||
| // the scale being zero. Eject all the fractional digits from the number. | ||
| result = result.div_wrapping(base.pow_wrapping(fractionals as _)); | ||
| digits -= fractionals as u8; | ||
| fractionals = 0; | ||
| } | ||
|
Comment on lines
+966
to
+972
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chainCore logic looks correct for zero-scale decimal handling. The implementation correctly discards fractional digits by dividing the result by 10^fractionals when scale is zero. The integer division properly truncates toward zero for both positive and negative values. Please verify that the new behavior works correctly with negative numbers (e.g., "-1.23" with scale 0 should parse to -1). Consider adding test cases for negative numbers in the 🏁 Script executed: #!/bin/bash
# Verify zero-scale decimal parsing with negative numbers
cat << 'EOF' | python
from decimal import Decimal
test_cases = [
("-1.0", -1),
("-1.2", -1),
("-1.9", -1),
("-123.45", -123),
("-0.99", 0),
]
print("Expected behavior for negative zero-scale decimals:")
for s, expected in test_cases:
d = Decimal(s)
actual = int(d)
status = "✓" if actual == expected else "✗"
print(f"{status} '{s}' -> {actual} (expected {expected})")
EOFLength of output: 202 Length of output: 1236 🌐 Web query: 💡 Result: Short answer: Rust's integer division (/) truncates toward zero. wrapping_div just computes self / rhs; for unsigned types that's identical to normal division, and for signed types it only "wraps" in the single overflow case MIN / -1 (it returns MIN). [1][2][3] Examples:
Sources:
Add test cases for negative numbers and Decimal256Type to zero_scale_tests. The core logic correctly truncates toward zero for negative numbers (confirmed: Rust's
Expand the test cases to include:
🤖 Prompt for AI Agents |
||
|
|
||
| if fractionals < scale { | ||
| let exp = scale - fractionals; | ||
| if exp as u8 + digits > precision { | ||
|
|
@@ -2636,6 +2644,7 @@ mod tests { | |
| ("12345678908765.123456", 3), | ||
| ("123456789087651234.56e-4", 3), | ||
| ("1234560000000", 0), | ||
| ("12345678900.0", 0), | ||
| ("1.23456e12", 0), | ||
| ]; | ||
| for (s, scale) in overflow_parse_tests { | ||
|
|
@@ -2752,6 +2761,23 @@ mod tests { | |
| let result = parse_decimal::<Decimal256Type>(s, 76, scale); | ||
| assert_eq!(i, result.unwrap()); | ||
| } | ||
|
|
||
| let zero_scale_tests = [ | ||
| ("1.0", 1), | ||
| ("1.2", 1), | ||
| ("1.00", 1), | ||
| ("1.23", 1), | ||
| ("1.000", 1), | ||
| ("1.123", 1), | ||
| ("123.0", 123), | ||
| ("123.4", 123), | ||
| ("123.00", 123), | ||
| ("123.45", 123), | ||
| ]; | ||
| for (s, i) in zero_scale_tests { | ||
| let result_128 = parse_decimal::<Decimal128Type>(s, 3, 0).unwrap(); | ||
| assert_eq!(i, result_128); | ||
| } | ||
| } | ||
|
|
||
| #[test] | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With scale == 0, this builds the entire fractional part into
resultand only then divides it out. For inputs with many fractional digits this can overflow/wrap the intermediate value (and counters), yielding an incorrect final value even though the post-division digits check passes.🤖 React with 👍 or 👎 to let us know if the comment was useful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
value:delightful; category:bug; feedback:The AI assistant is correct that the wrapping would lead to problems if there are more than 10 fractional digits if
baseis 32bit integer or more than 20 fractional digits if thebaseis 64bit integer