Format decimal numbers with BigDecimal instead of Float - #386
Open
gaoflow wants to merge 1 commit into
Open
Conversation
Decimal#apply coerced every value to Float before formatting, so the shared Number engine (Decimal, Currency and Percent) inherited three defects: half-up rounding instead of CLDR's half-even, scientific notation for magnitudes >= 1e15 (10**15 formatted as "1.0e+15"), and lost digits above 2**53. Route through BigDecimal so rounding is exact half-even per UTS ruby-i18n#35 and large integers format as grouped digits.
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.
Decimal#applycoerces every number toFloatbefore formatting, so the sharedNumberengine (behindDecimal,CurrencyandPercent) inherits three defects from that one conversion:round_tousesFloat#round; CLDR / UTS Export exemplar characters #35 rounds half-even, as do ICU and Babel.Decimal.new("0").apply(2.5)returns"3"(should be"2"), andapply(0.125)at"0.00"returns"0.13"(should be"0.12").Float#to_srenders10**15as"1.0e+15"andsplit(".")shreds it, soNumber.new("#,##0").apply(10**15)returns"1.0e+15"-- invalid output for an exact value. The repo's ownIntegerformatter already returns"1,000,000,000,000,000"here.Float(12345678901234567890)drops digits before formatting.The fix routes formatting through
BigDecimaland rounds half-even, so rounding is exact and large integers never reach scientific notation. The rounding change touches only exact binary halves (n.5,n/8); artifacts such as2.675(not exactly 2.675 in binary) are unchanged. Expected values in the tests were cross-checked against ICU and Babel 2.17.Tested: the decimal, number, currency and percent suites pass (e.g.
bundle exec ruby test/format/decimal/number_test.rb). The currency and percent test files were empty and now cover the shared rounding path.