Skip to content

std.format %e/%g do not follow documented Python rounding semantics #1327

@He-Pin

Description

@He-Pin

std.format is documented as following Python formatting rules:
https://jsonnet.org/ref/stdlib.html#std-format

In jsonnet v0.22.0, %e/%g do not renormalize the mantissa when rounding carries from 9... to 10.... %g precision 0 also appears to be passed through as a negative fractional precision, while Python treats precision 0 for %g as precision 1.

Repro table:

Expression Python 3 C++ jsonnet v0.22.0 go-jsonnet v0.22.0 jrsonnet v0.5.0-pre99
"%.0g" % 1.0 "1" "5e+00" "5e+00" "0e+00"
"%+.0g" % 1.0 "+1" "+5e+00" "+5e+00" "+0e+00"
"%.0g" % 0.1 "0.1" "5" "5" "0"
"%.1g" % 9.9 "1e+01" "10" "10" "10"
"%.2g" % 99.9 "1e+02" "100" "100" "100"
"%.0e" % 9.5e10 "1e+11" "10e+10" "10e+10" "10e+10"
"%.1e" % 9.99 "1.0e+01" "10.0e+00" "10.0e+00" "10.0e+00"

Commands used:

python3 - <<PY
for expr in [1.0, 0.1, 9.9, 99.9, 9.5e10]:
    pass
print("%.0g" % 1.0)
print("%+.0g" % 1.0)
print("%.0g" % 0.1)
print("%.1g" % 9.9)
print("%.2g" % 99.9)
print("%.0e" % 9.5e10)
print("%.1e" % 9.99)
PY

jsonnet -e '["%.0g" % 1.0, "%+.0g" % 1.0, "%.0g" % 0.1, "%.1g" % 9.9, "%.2g" % 99.9, "%.0e" % 9.5e10, "%.1e" % 9.99]'

Likely cause:

In stdlib/std.jsonnet, %g calls render_float_dec/sci with fpprec - 1, so %.0g passes -1 precision into the renderer. Separately, the renderer rounds the mantissa but does not normalize 10 * 10^precision back to 1 * 10^precision with exponent + 1.

This is related in spirit to #879, but that issue was about fixed-point carry for %f-style formatting. This issue covers %e/%g scientific renormalization and %g precision-zero behavior.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions