fix: round formatted doubles ties-to-even - #1116
Merged
stephenamar-db merged 1 commit intoAug 11, 2026
Merged
Conversation
Motivation: std.format mixed shortest-decimal and binary64 intermediate rounding, producing mathematically incorrect results such as 1.005 -> 1.01 and inconsistent behavior across precisions and conversions. Modification: round the exact binary64 value once with HALF_EVEN for fixed, scientific, and generic formats, update exponent selection, and expand regression coverage. Result: %f, %e, and %g now consistently follow Python-style round-to-nearest ties-to-even semantics across tested precisions and platforms.
He-Pin
marked this pull request as draft
August 9, 2026 08:32
He-Pin
marked this pull request as ready for review
August 9, 2026 09:09
He-Pin
marked this pull request as draft
August 9, 2026 09:10
He-Pin
marked this pull request as ready for review
August 11, 2026 13:13
stephenamar-db
approved these changes
Aug 11, 2026
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.
Motivation
Jsonnet documents
std.formatas following the same formatting rules as Python. sjsonnet previously mixed decimal sources and rounding mechanisms:+ 0.5followed byFLOOR.Math.round, while high-precision paths could switch to exactBigDecimal.That made the result depend on the conversion path. For example, old sjsonnet produced
1.01forstd.format("%.2f", 1.005), while exact binary64 formatting produces1.00; exact midpoint cases such asstd.format("%.0f", 2.5)also produced3instead of Python's ties-to-even result2.The target contract in this PR is: format the represented finite IEEE 754 binary64 value, perform exactly one rounding step, and use round-to-nearest, ties-to-even.
Modification
BigDecimal.exact(number).HALF_EVENonce for positive-precision fixed formatting and all scientific formatting.math.rintfor zero-precision fixed formatting.%gdecides whether rounding crosses an exponent boundary.%f/%e/%gconsistency.Result
Cross-implementation comparison
The following outputs were measured locally with the same format/input pairs: one shared Jsonnet expression for the Jsonnet implementations and equivalent percent-format expressions in CPython. JSON string quotes are omitted in the table.
ce6652f0(the PR base commit)v0.21.00.5.0-pre993.14.500f52495(this PR)%.0f0.511100%.0f2.533322%.1f0.250.30.30.30.20.2%.2f0.0150.020.020.020.010.01%.2f1.0051.011.001.001.001.00%.2f2.6752.682.682.682.672.67%.0e2.5e103e+103e+103e+102e+102e+10%.1g2.533322The table separates two issues:
1.005exposes the old sjsonnet-only shortest-decimal path; go-jsonnet and jrsonnet happen to produce1.00after their binary64 intermediate rounds below the decimal midpoint.The same eight-case expression produced identical arrays for CPython and the new sjsonnet implementation.
Validation
./mill __.test:2065/2065tasks passed across JVM, JS, Wasm, and Native../mill __.checkFormat:36/36tasks passed.2,029,200cases, zero differences.References and risks
References
std.formatRisks
%f,%e, and%g.BigDecimal/BigIntarithmetic replaces low-precision fast paths and can be slower in formatting-heavy workloads. This PR does not claim a performance-neutral change.