Re: [PR] Fix printDecimal regression for decimal values wide r than a long [poi-xmlbeans]
pjfanning (via GitHub) <[email protected]>
| Newsgroups | gmane.comp.jakarta.poi.devel |
|---|---|
| Message-ID | <PR_kwDOAAQgj88AAAABBIne4w-27a1404d-1ba9-4e26-9f30-848dad89a9ac@gitbox.apache.org> |
pjfanning commented on PR #96:
URL: https://github.com/apache/poi-xmlbeans/pull/96#issuecomment-5431767105
Thanks for the patch and for the clear write-up - the diagnosis is right, and the operand swap is a pure short-circuit reordering with no semantic change (under `scale < 0` the value is integral, so `toLong(v) == 0` and `signum() == 0` agree whenever `toLong` doesn't throw). It does fix the reported case.
However, I think it's an incomplete fix: the `scale < 0` guard doesn't stop `toLong()` from throwing, it only narrows which values reach it. Negative-scale decimals wider than a long still fail the same way after the patch:
```
1E+20 scale=-20 -> IllegalArgumentException: Value can't be converted to long
-1E+20 scale=-20 -> IllegalArgumentException: Value can't be converted to long
1E+2000 scale=-2000 -> IllegalArgumentException: BigDecimal magnitude too large to convert safely (limit 1024)
```
That shape isn't hypothetical - `new BigDecimal("100000000000000000000").stripTrailingZeros()` is exactly `1E+20`, and `BigDecimal.valueOf(unscaled, negativeScale)` gives the same. Values set programmatically via `setBigDecimalValue` reach `printDecimal` that way (the lexer path can't, since `lexDecimal` rejects exponents).
`MathUtil.toLong(value) == 0` is really standing in for "is this value zero" - Harmony's original line was `if (scale == 0 || (isZero() && scale < 0))`. So I'd suggest using `signum()` directly instead: same semantics, can't throw, O(1), and it takes `MathUtil` off the serialization path entirely:
```java
if (scale == 0 || (value.signum() == 0 && scale < 0)) {
return intStr;
}
```
I ran the full `printDecimal` body with that condition:
```
1E+20 -> 100000000000000000000
-1E+20 -> -100000000000000000000
0E+5 -> 0
0E-5 -> 0.00000
100 / 1E+2 -> 100
123456789012345678901234567890.5 -> 123456789012345678901234567890.5 (both signs)
```
all correct, including the zero-with-negative-scale case the branch exists for.
On the test: `printDecimalHandlesValuesWiderThanLong` only covers `scale > 0`. Worth adding the negative-scale cases, since those are the ones left broken today:
```java
assertEquals("100000000000000000000", XsTypeConverter.printDecimal(new BigDecimal("1E+20")));
assertEquals("-100000000000000000000", XsTypeConverter.printDecimal(new BigDecimal("-1E+20")));
assertEquals("0", XsTypeConverter.printDecimal(new BigDecimal("0E+5")));
```
Minor: with the `signum()` version the inline comment can be simplified to just say the branch only needs a zero check, which is what Harmony did.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]