Skip to content

Rounding Options Puzzle #8

@sffc

Description

@sffc

I have a puzzle which has perplexed me.

Below, I list real-life use cases for how users want to round their numbers in Intl.NumberFormat. I am trying to figure out some set of options that is capable of expressing these various different rounding strategies.

Compact Notation Rounding

Input Style 1 Style 2 Style 3
1,234,000 1234K 1234K 1234K
123,400 123K 123K 123K
12,340 12K 12K 12.3K
1,234 1.2K 1.2K 1.23K
1,034 1K 1.0K 1.03K
.1034 .1 .10 .103
.1234 .12 .12 .123

English Descriptions

  • Style 1: When there are 2 or more digits before the decimal separator, round to the nearest integer. Otherwise, round to 2 significant digits. Strip trailing zeros.
  • Style 2: When there are 2 or more digits before the decimal separator, round to the nearest integer. Otherwise, round to 2 significant digits. Retain trailing zeros.
  • Style 3: When there are 3 or more digits before the decimal separator, round to the nearest integer. Otherwise, round to 3 significant digits. Strip trailing zeros.

Thoughts

Style 1 could be expressed as minFrac=0, maxFrac=0, and minSig=2, and when minSig is in conflict with maxFrac, minSig wins, except that we strip trailing zeros. In other words, we could make Style 1 be expressed as:

{
  minimumFractionDigits: 0,
  maximumFractionDigits: 0,
  minimumSignificantDigits: 2
}

However, this approach is not capable of expressing Style 2.

We could have an option like "applyFractionGreaterThanIntDigits", which would mean to use minFrac/maxFrac when there are a certain number of integer digits, and minSig/maxSig when there are fewer. This is not a very pretty option, but it is capable of expressing all three styles:

Option Style 1 Style 2 Style 3
minimumFractionDigits 0 0 0
maximumFractionDigits 0 0 0
minimumSignificantDigits 1 2 1
maximumSignificantDigits 2 2 3
applyFractionGreaterThanIntDigits 2 2 3

Currency Rounding

Input Style 1 Style 2 Style 3 Style 4
1 $1.00 $1 $1.00 $1.00
1.01 $1.01 $1.01 $1.00 $1.00
1.04 $1.04 $1.04 $1.05 $1.00
1.12 $1.12 $1.12 $1.10 $1.10

English Descriptions

  • Style 1: Round with 2 fixed fraction digits.
  • Style 2: Round with 2 fixed fraction digits, but strip trailing zeros if the fraction is zero.
  • Style 3: Nickel rounding: round to the nearest 0.05; display 2 fraction digits.
  • Style 4: Dime rounding: round to the nearest 0.1; display 2 fraction digits.

Thoughts

A simple boolean option "stripFractionWhenEmpty" would solve Style 2.

A simple boolean option "nickelRounding" would solve Style 3.

About Trailing Zeros

Note that minFrac already serves absolutely no purpose other than retaining trailing zeros.

Given that minFrac is really only about retaining trailing zeros, for Style 4, we could let minFrac be greater than maxFrac, but it is weird for a minimum to be greater than a maximum.

Since a lot of the problems in this section, as well as Style 2 in the previous section, involve various different ways of treating trailing zeros, maybe we could introduce a "trailingZeroStyle" option, an enum with several different options that encompass all of the use cases.

Distance Rounding

Input Style 1 Style 2
60 50 yards 50 yards
220 200 yards 200 yards
450 450 yards 450 yards
490 500 yards 500 yards
530 550 yards 500 yards
590 600 yards 600 yards

English Descriptions

  • Style 1: Round to the nearest 50.
  • Style 2: Round to the nearest 50 when below 500, and the nearest 100 when above 500.

Thoughts

Style 1 can be represented by a variant of nickelRounding. We could name the option nickelRoundingMagnitude, and if set, it would override fraction and significant rounding. Alternatively, we could allow minFrac/maxFrac to be less than zero, in which case they express the power of 10 at which you round.

Style 2 involves a cutoff. If we can't figure out how to support it, we could declare it out of scope.

Maybe we should throw the minFrac/maxFrac stuff out the door (keep it for backwards compatibility), and devise a whole new way of thinking about rounding strategies.

@echeran @ryzokuken

Metadata

Metadata

Assignees

No one assigned

    Labels

    has-consensusHas consensus and ready to implement

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions