Skip to content
This repository has been archived by the owner on Jan 26, 2022. It is now read-only.

Rounding Behavior in Compact Notation #9

Closed
sffc opened this issue Jul 17, 2018 · 7 comments
Closed

Rounding Behavior in Compact Notation #9

sffc opened this issue Jul 17, 2018 · 7 comments

Comments

@sffc
Copy link
Collaborator

sffc commented Jul 17, 2018

ICU overrides the default rounding strategy when compact notation is used. ICU's compact rounding strategy is to round to the nearest integer, except to add a single digit after a decimal separator if to ensure there are always at least two significant digits shown:

  • 1.2K
  • 12K
  • 123K
  • 1.2M
  • 12M
  • 123M

Should this rounding strategy be defaulted when compact notation is used in ECMAScript, or should the default rounding strategy of 3 fraction digits be used, and leave it up to the user to override it?

@littledan
Copy link
Member

I'd suggest, when no rounding options are passed in, ICU's rounding strategy should be used (and this should be reflected in resolvedOptions()); when rounding options are passed in, those should be respected. This would mirror what is done for currencies.

@sffc
Copy link
Collaborator Author

sffc commented Jul 17, 2018

Okay.

An issue is that ICU's rounding strategy cannot be expressed as either fraction digit rounding or as significant digit rounding. It needs a new construct.

See this ticket for more context:

https://unicode-org.atlassian.net/browse/ICU-20019

I have been working on this puzzle for a year and a half, and I still haven't come up with a clean API that covers all of the cases in the table on that bug, which I will reproduce here:

Description In ICU? 3.1 3.01 0.03333 32.1 65432
Nearest integer Y 3 3 0 32 65432
Nearest integer, keep two significant digits, no trailing zeros Y 3.1 3 0.033 32 65432
Nearest integer, keep two significant digits, trailing zeros N 3.1 3.0 0.033 32 65432
Nearest integer, keep two significant digits but not more than three, no trailing zeros N 3.1 3 0.033 32 65400
Nearest integer, keep two significant digits but not more than three, trailing zeros N 3.1 3.0 0.033 32 65400
Max three significant digits Y 3.1 3.01 0.0333 32.1 65400
Max three significant digits, but no more than one fraction digit, no trailing zeros N 3.1 3 0 32.1 65400
Max three significant digits, keep two significant digits, but no more than one fraction digit, trailing zeros N 3.1 3.0 0.0 32.1 65400
Nearest integer, keep two significant digits but not more than three, no more than one fraction digit, no trailing zeros N 3.1 3 0 32 65400
Nearest integer, keep two significant digits but not more than three, no more than one fraction digit, trailing zeros N 3.1 3.0 0.0 32 65400

ICU compact notation currently uses the second row, but internally at Google we've had requests to move to some of the other options in this table.

Can you help brainstorm an API for Intl.NumberFormat that is capable of expressing a larger subset of these rounding strategies?

@sffc
Copy link
Collaborator Author

sffc commented Jul 19, 2018

tc39/ecma402#239 is related.

@sffc
Copy link
Collaborator Author

sffc commented Jul 19, 2018

@srl295 also suggested that we should include rounding increments (nickel rounding) since those are required by some currency implementations.

@sffc
Copy link
Collaborator Author

sffc commented Aug 3, 2018

As you can see from ICU-20019, I haven't really come up with a super nice way of expressing these various strategies, and it also isn't obvious that we really need so much API surface to control this.

What do you think about supporting a function parameter that performs the rounding? The function really needs only one parameter: the magnitude of the most significant digit, i.e., ⌊log10(x)⌋. For example, for the default ICU compact notation rounding strategy, the function would look like this:

function(magnitude) {
  if (magnitude < 1) {
    return magnitude - 1;
  } else {
    return 0;
  }
}

That function produces the second row in my table. To support trailing zeros, the function could be,

function(magnitude) {
  if (magnitude < 1) {
    return {
      roundTo: magnitude - 1;
      trailingZerosTo: magnitude - 1;
    };
  } else {
    return 0;
  }
}

It may or may not be important to support different trailing zero behavior based on whether or not digits were "rounded off" the end. For example:

Trailing Zeros? 3 3.01
Always 3.0 3.0
Never 3 3
If Rounded 3 3.0

If we wanted to support this, we could make the function return an object with three fields:

{
  roundTo: ___,
  trailingZerosAlwaysTo: ___,
  trailingZerosIfRoundedTo: ___
}

Another issue is that in some cases you might want different rounding behavior in different locales. For example, suppose you want to render the number 987654321 in en-US. You might say, "988,000,000". However, in en-IN, since grouping is different, you might round differently, as in, "99,00,00,000". I don't have any studies to say whether this is actually the case, but it seems like we should at least consider the fact that rounding could be locale-sensitive.

@littledan
Copy link
Member

I'm glad you are putting in this detailed thought here. I am not sure if what the problem is if the default rounding strategy can't be expressed in terms of other primitives; resolvedOptions can be a separate representation. For nickel rounding, that seems very useful, but if an API hasn't been figured out, I think we can just expect it to be done at the application level for now, and provide support in a follow-on proposal.

@sffc
Copy link
Collaborator Author

sffc commented Aug 4, 2018

I see, so for now make the spec implement the rounding strategy needed for compact notation, but don't expose it right now on the API level. That makes sense.

@sffc sffc closed this as completed in 925b7ee Oct 24, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants