Skip to content

fix: format high-precision scientific numbers exactly - #1095

Merged
stephenamar-db merged 2 commits into
databricks:masterfrom
He-Pin:fix/format-scientific-high-precision
Jul 30, 2026
Merged

fix: format high-precision scientific numbers exactly#1095
stephenamar-db merged 2 commits into
databricks:masterfrom
He-Pin:fix/format-scientific-high-precision

Conversation

@He-Pin

@He-Pin He-Pin commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Motivation

The old scientific path scaled in Double and rounded through Long. Precision above 15 could lose meaningful binary64 digits; precision ≥19 saturated at Long.MaxValue, producing silent wrong answers (e.g. std.format("%.19e", 1.5)1.000...e+00).

Modification

  • For scientific precision >15, use BigDecimal.exact(number) with BigInt mantissa scaling.
  • Round with half-even semantics; propagate carry into exponent without Long narrowing.
  • Add regressions for precision 16–20, exponent boundaries, exact ties, signed zero, %E.

Result

Expression before after go-jsonnet jrsonnet Python
std.format("%.16e", 3.14159265358979323) 3.1415926535897932e+00 3.1415926535897931e+00 3.1415926535897932e+00 3.1415926535897932e+00 3.1415926535897931e+00
std.format("%.19e", 1.5) 1.0000000000000000000e+00 1.5000000000000000000e+00 1.5000000000000000000e+00 1.5000000000000000000e+00 1.5000000000000000000e+00
std.format("%.19e", 0.1) 1.0000000000000000000e-01 1.0000000000000000555e-01 1.0000000000000000000e-01 1.0000000000000000000e-01 1.0000000000000000555e-01
std.format("%.20e", 3.14) 1.00000000000000000000e+00 3.14000000000000012434e+00 3.14000000000000000000e+00 3.09223372036854775807e+00 3.14000000000000012434e+00

This PR matches Python's formatting model from the exact binary64 value. Full matrix (JVM/JS/Wasm/Native) + checkFormat passed.

References

Motivation:
Scientific formatting scaled binary64 values in Double and rounded through
Long. Precision above 15 lost low-order digits, and precision 19 or greater
could saturate at Long.MaxValue and silently replace the mantissa.

Modification:
Use the exact binary64 magnitude, BigInt scaling, half-even rounding, corrected
decimal-exponent bounds, and carry handling for scientific precision above 15.
Add regressions for precision 16 through 20, decade boundaries, ties, signed
zero, and uppercase formatting.

Result:
High-precision %e/%E output no longer saturates and matches Python formatting
from the same IEEE-754 value, including exact trailing digits.

References:
- databricks#1095
- https://jsonnet.org/ref/stdlib.html#std-format
@He-Pin
He-Pin force-pushed the fix/format-scientific-high-precision branch from f291f79 to eb3f89d Compare July 29, 2026 08:27
@He-Pin He-Pin changed the title Fix high-precision scientific formatting fix: format high-precision scientific numbers exactly Jul 29, 2026
Motivation:
The original test only covered precision 16-20 with moderate values.
Double.MaxValue, the smallest subnormal, and precision > 20 were
verified manually but not regression-protected.

Modification:
Add assertions for Double.MaxValue (%.20e), smallest subnormal 5e-324
(%.20e), precision 40, precision 25, and pi at precision 30.

Result:
Extreme edge cases are now locked in against future regressions.
stephenamar-db pushed a commit that referenced this pull request Jul 30, 2026
## Motivation

`BigDecimal(number)` uses the shortest round-trip decimal, not the exact
binary64 value. When `%f` or fixed-form `%g` requested >15 digits,
sjsonnet padded the shortened decimal and hid meaningful trailing
digits.

## Modification

- Use `BigDecimal.exact(number)` for fixed formatting above 15
fractional digits.
- Propagate `%g`'s significant precision so its fixed-form path can
select exact conversion.
- Round the exact path with half-even semantics; preserve existing
low-precision behavior.
- Add non-tie, retained-even/odd halfway, negative halfway, and
fixed-form `%g` regressions.

## Result

| Expression | before | after | go-jsonnet | jrsonnet | Python |
| --- | --- | --- | --- | --- | --- |
| `std.format("%.16f", 3.14159265358979323)` | `3.1415926535897930` |
`3.1415926535897931` | `3.1415926535897932` | `3.1415926535897932` |
`3.1415926535897931` |
| `std.format("%.17f", 0.1)` | `0.10000000000000000` |
`0.10000000000000001` | `0.10000000000000000` | `0.10000000000000002` |
`0.10000000000000001` |
| `std.format("%.17f", 3.14159265358979323)` | `3.14159265358979300` |
`3.14159265358979312` | `3.14159265358979328` | `3.14159265358979328` |
`3.14159265358979312` |
| `std.format("%.17g", 31.4159265358979323)` | `31.41592653589793` |
`31.415926535897931` | `31.415926535897932` | `31.415926535897932` |
`31.415926535897931` |

Half-even rounding verified against go-jsonnet, jrsonnet, and Python.
Full matrix (JVM/JS/Wasm/Native) + `checkFormat` passed.

High-precision scientific notation is handled separately in #1095.

## References

- [Jsonnet `std.format`](https://jsonnet.org/ref/stdlib.html#std-format)
- [Python printf-style
formatting](https://docs.python.org/3.9/library/stdtypes.html#printf-style-string-formatting)
@stephenamar-db
stephenamar-db merged commit dd602d3 into databricks:master Jul 30, 2026
5 checks passed
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.

2 participants