google / google/jsonnet

std.format: wrong digits for %f/%d on large values; malformed output for non-integer * precision

Open
#1,331 0 comments 0 reactions 0 assignees View on GitHub
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.