Skip to content

pxf: a BigFloat literal far past the bound is refused in this port's words, not Go's #144

Closed

Description

@bfrancojr

For a BigFloat literal far past MaxBigFloatExponent, this port and protowire-go give different error texts. Both refuse it. Found while working on #125 (PR #142).

Measured with both ports' check_decode --format pxf-pb, protowire-go at 207fdfc, this repo at a632c6e:

literal protowire-go this port
1e-100000p64 big float literal 1e-100000 has binary exponent -332192, and MaxBigFloatExponent=16384 bounds its magnitude big float literal 1e-100000 is past MaxBigFloatExponent=16384
1e20000p64 ... has binary exponent 66439, and MaxBigFloatExponent=16384 bounds its magnitude ... is past MaxBigFloatExponent=16384
1e4940p64 (just past) ... has binary exponent 16411, ... same as Go

Cause. ParseBigFloatLiteral (src/pxf/bigfloat.cc) has a fast check before it builds 10^exp10. If the decimal point position puts the value certainly past the bound (reach), it refuses with its own text. That check is there so a literal like 1e-999999999999 costs nothing. Go doesn't have it: big.Float.Parse works at a fixed precision, so Go can report the binary exponent cheaply.

Two smaller effects of the same check:

  • When a value is both far past the bound and below the wire's exponent range (1e-100000p2147483647), Go reports "below the wire's exponent range" and this port reports "is past". Go asks the wire range first.
  • Past big.Float's own exponent range, Go reports is above big.Float's range / is below big.Float's range. This port reports "is past".

Options.

  1. Compute the exact binary exponent of digits * 10^exp10 without building 10^exp10, using a high-precision log2(10) and an exact fallback near integers. Then use Go's text and Go's order. Cost stays bounded.
  2. Replicate Go's message using a binary exponent from big.Float.Parse's working precision. That is closer to Go's double rounding than to the exact value.
  3. Keep the text, and record the difference in the spec's error-text tolerance, if one exists.

Not decided. The texts are not compared by the spec's security gate, which reads only verdicts. scripts/go_differential.sh would flag them if a fixture reached this path; none does now.

Done when: such a literal is refused with Go's text, in Go's order of checks, pinned by a test with the literals above.

Activity

  1. bfrancojr commented on Nov 4, 2026

    @bfrancojr
    CollaboratorAuthor

    Recommendation, still for the owner to decide: match Go's text and order of checks exactly. Option 3 (keep this port's text) goes against the standing rule that protowire-go is the golden behaviour.

    Between options 1 and 2, the deciding test is whether the port reproduces Go's exponent numbers (-332192, 66439, 16411, ...) on a sweep of literals near powers of ten and near integer log2 values. Go reports the exponent of big.Float.Parse's rounded result. So option 1's exact exponent may be off by one where that rounding carries, and only the sweep can show it.

    Classification: reversible by a revert; local (error text only, no type or wire change); inferred, not measured; latent (no gate compares these texts today).

    What would flip it: a spec rule that tolerates port-specific error text. That would make option 3 acceptable.

  2. bfrancojr commented on Nov 5, 2026

    @bfrancojr
    CollaboratorAuthor

    Decided by the owner (2026-11-05): match Go's text and order of checks. Between options 1 and 2, pick whichever reproduces Go's exponent numbers on a sweep of literals near powers of ten and near integer log2 values.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions