Skip to content

fix: handle negative-scale Decimals in increment, decrement and truncate_decimal - #4285

Open
AP24110011695 wants to merge 1 commit into
apache:mainfrom
AP24110011695:fix/decimal-negative-scale-remnants
Open

AP24110011695 wants to merge 1 commit into
apache:mainfrom
AP24110011695:fix/decimal-negative-scale-remnants

Conversation

@AP24110011695

Copy link
Copy Markdown

Fixes #4284

Problem

Decimal.as_tuple().exponent carries the negated scale, so Decimal("1E+2") (100) has exponent +2, i.e. scale -2. Three remaining call sites still read the scale as abs(int(exponent)), which turns that -2 into +2:

  • DecimalLiteral.increment(): 1E+2 stepped to 0.02 instead of 2E+2
  • DecimalLiteral.decrement(): 1E+2 stepped to 0.00 instead of 0E+2
  • truncate_decimal(): 1.5E+3 truncated to 0.12 instead of 1.2E+3

Same root cause as #3997 (which fixed the to(DecimalType) / serialize sites); this PR fixes the remaining ones. For all positive-scale Decimals the two formulas are identical, so behavior only changes for negative-scale values, where it was wrong.

Tests

Failing-first regression tests, all verified locally (Python 3.12, Windows):

  • test_decimal_literal_increment_negative_scale / test_decimal_literal_decrement_negative_scale (extended tests/expressions/test_literals.py, mirroring the existing increment/decrement tests)
  • test_truncate_decimal (first coverage for this helper's normal path, including the floor-toward-negative-infinity case) + test_truncate_decimal_negative_scale in tests/utils/test_decimal.py

All 4 tests fail on main and pass with this change. Full tests/expressions/test_literals.py (182 passed), tests/utils/test_decimal.py, and tests/test_transforms.py (275 passed; the 17 pyarrow-parametrized failures in that file fail identically on unmodified main in this environment). ruff (pinned 0.14.3) format + check clean on all touched files; mypy (1.18.2, repo config) clean on the changed module.


Transparent disclosure: developed and verified with AI assistance under human direction, per the repo's agent guidelines.

…ate_decimal

Decimal.as_tuple().exponent carries the negated scale, so a Decimal with a
non-negative exponent (1E+2) has a negative scale. abs() turned that exponent
into a positive scale, so increment()/decrement() returned values on the wrong
order of magnitude (1E+2 -> 0.02 instead of 2E+2) and truncate_decimal() landed
on a wrong scale. Same root cause as apache#3997, remaining call sites.

Signed-off-by: Ayush Kumar Saha <225407166+AP24110011695@users.noreply.github.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Negative-scale Decimals (e.g. 1E+2) are corrupted by DecimalLiteral.increment/decrement and truncate_decimal

1 participant