Preserve exact value in BigDecimal and BigInteger validate#406
Merged
garydgregory merged 1 commit intoJun 20, 2026
Merged
Conversation
garydgregory
added a commit
that referenced
this pull request
Jun 20, 2026
- Sort members. - Reduce vertical whitespace.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Following up on the earlier range-check work I checked what validate() actually hands back for high-precision input, and both validators drop digits. BigDecimalValidator.validate("0.12345678901234567890") returns 0.12345678901234568, and BigIntegerValidator on an integer past the long range (92233720368547758077) returns 92233720368547760000. The parse runs through the inherited NumberFormat, whose default DecimalFormat returns a Double for any fractional value or any integer outside long range, so the value is already rounded to roughly 17 significant figures before it is wrapped in a BigDecimal or BigInteger. For a pair of classes whose whole purpose is exact conversion that is a real correctness problem, and it is silent: no exception, just a different value than the caller supplied.
Overriding getFormat in each validator to put the DecimalFormat into setParseBigDecimal(true) makes parseObject return a BigDecimal up front, so the exact value reaches the conversion step. It belongs at the format layer because that is where the lossy Double is created, and nothing downstream can recover digits that parsing has already discarded. The two validators are kept in step, which an existing test already pins to the same magnitude, and one fixture that encoded the rounded result has been updated to the exact value. New regression tests cover a high-precision decimal and an integer scaled up from Long.MAX_VALUE.