std.format: wrong digits for %f/%d on large values; malformed output for non-integer * precision
- Dominant language
- Jsonnet
- Stars
- 7.6k
- Forks
- 475
- PR merge metrics
- No merged PRs in 30d
Description
## Description
The numeric conversion codes of `std.format`, as implemented in `std.jsonnet`, produce wrong digits for large values and accept non-integer `*` width/precision, producing malformed output. Verified on go-jsonnet v0.22.0 (which vendors `std.jsonnet`); since the implementation lives in the shared stdlib, I expect the C++ implementation is affected the same way (I did not test a C++ binary locally).
Per https://jsonnet.org/ref/stdlib.html#std-format, "string formatting follows the same rules as Python", so CPython is used as ground truth below.
## 1. `%f` wrong fractional digits for large integral doubles
```jsonnet
std.format("%f", 1e20)
```
- Actual: `"100000000000000000000.729344"`
- Expected: `"100000000000000000000.000000"`
CPython:
```python
>>> "%f" % 1e20
'100000000000000000000.000000'
```
`1e20` is an exactly-representable integer double, so the fraction must be all zeros. The `.729344` suggests the fraction is extracted with floating-point arithmetic that loses precision at this magnitude.
## 2. `%d` wrong digits for large doubles
```jsonnet
std.format("%d", 1e308)
```
- Actual (first digits): `100000000000000080820288064406668826404226602626644826268666088682448264248040264260482460802080684648080264248284000422088262400264842228240488280204820482448600044082048226820886002048022200064204444666088046048242682004206408240604042624800242804426482484064246602062860886000088448826682264040666006840886`
- Expected (exact decimal expansion of the binary64 value): `100000000000000001097906362944045541740492309677311846336810682903157585404911491537163328978494688899061249669721172515611590283743140088328307009198146046031271664502933027185697489699588559043338384466165001178426897626212945177628091195786707458122783970171784415105291802893207873272974885715430223118336`
CPython agrees with Expected:
```python
>>> "%d" % 1e308
100000000000000001097906362944045541740492309677311846336810682903157585404911491537163328978494688899061249669721172515611590283743140088328307009198146046031271664502933027185697489699588559043338384466165001178426897626212945177628091195786707458122783970171784415105291802893207873272974885715430223118336
```
## 3. Non-integer `*` width/precision yields malformed output instead of an error
```jsonnet
std.format("%.*f", [2.5, 1.234])
```
- Actual: `"1.73.772233983161982"` (malformed: two decimal points)
- Expected: an error; CPython raises `TypeError: * wants int`
Similarly `std.format("%*d", [2.5, 42])` silently truncates the width to 2 instead of erroring.
## Cross-check
sjsonnet produces the Expected output in all three cases (its `%d`/`%f` paths expand the exact binary64 value and validate `*` arguments are integers).
## Environment
- go-jsonnet v0.22.0 (Homebrew), used as the vehicle to exercise the shared `std.jsonnet` formatting code.
Contributor guide
Research direction
The issue identifies the shared std.jsonnet formatting implementation and provides three reproductions, expected outputs, and a sjsonnet cross-check. Start by reproducing the %f, %d, and non-integer * cases, then compare the shared implementation with Python and sjsonnet; done means exact large-value digits and errors for non-integer width or precision.
Written by the indexing model from the issue text.
Assessment
- Domain
- tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100