Skip to content

NumberFormat roundingIncrement precision loss for large increments and missing roundingPriority #635

@frostney

Description

@frostney

Summary

Two remaining NumberFormat formatting gaps after #595 / #598 work:

  1. roundingIncrement produces wrong results for large increments (1000, 2000, 2500, 5000) because ApplyRoundingIncrement in IntlICU.pas scales the value by 10^maxFractionDigits before dividing by the increment — when the increment equals or exceeds the scale factor, the intermediate value loses precision (e.g. 1000 / 1000 = 1.0 collapses the fractional information).

  2. roundingPriority ("lessPrecision" / "morePrecision") is not implemented. This ECMA-402 feature coordinates between minimumFractionDigits/maximumFractionDigits and minimumSignificantDigits/maximumSignificantDigits to pick the tighter or looser bound at format time.

Why

7 intl402 test262 tests fail on the "latn" numbering system path (previously hidden behind a missing numberingSystem field, surfaced by #595):

  • format-rounding-increment-{1000,2000,2500,5000}.js
  • format-rounding-priority-{less-precision,more-precision}.js
  • test-option-roundingPriority-mixed-options.js

Current behavior

new Intl.NumberFormat("en", {
  roundingIncrement: 1000, maximumFractionDigits: 3, minimumFractionDigits: 3
}).format(1.0005)
// Wrong output (precision loss in scaled arithmetic)

new Intl.NumberFormat("en", {
  roundingPriority: "lessPrecision",
  minimumFractionDigits: 1, maximumFractionDigits: 3,
  minimumSignificantDigits: 3, maximumSignificantDigits: 3
}).format(1)
// roundingPriority is ignored; falls back to fractionDigits only

Expected behavior

// roundingIncrement: grid is 0.000, 1.000, 2.000, ...
// 1.0005 rounds to 1.000
new Intl.NumberFormat("en", {
  roundingIncrement: 1000, maximumFractionDigits: 3, minimumFractionDigits: 3
}).format(1.0005)
// "1.000"

// roundingPriority: "lessPrecision" picks the tighter of the two constraints
new Intl.NumberFormat("en", {
  roundingPriority: "lessPrecision",
  minimumFractionDigits: 1, maximumFractionDigits: 3,
  minimumSignificantDigits: 3, maximumSignificantDigits: 3
}).format(1)
// "1.00"

Scope notes

Metadata

Metadata

Assignees

No one assigned

    Labels

    engineTGocciaEngine: language semantics, ECMAScript built-ins, parser, interpreter, bytecode VM

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions