-
Notifications
You must be signed in to change notification settings - Fork 12
Add limits to Intl MV #128
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
numberformat/diff.emu
Outdated
@@ -1592,7 +1592,12 @@ | |||
1. Let _text_ be ! StringToCodePoints(_str_). | |||
1. Let _literal_ be ParseText(_text_, |StringNumericLiteral|). | |||
1. If _literal_ is a List of errors, return ~not-a-number~. | |||
1. Return the StringIntlMV of _literal_. | |||
1. Let _intlMV_ be the StringIntlMV of _literal_. | |||
1. If _intlMV_ is a mathematical value and _intlMV_ > ℝ(Number.MAX_VALUE), the implementation may set _intlMV_ to ~positive-infinity~. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: % to refer to the original value of Number.MAX_VALUE
. (Also for the other references below.)
1. If _intlMV_ is a mathematical value and _intlMV_ > ℝ(Number.MAX_VALUE), the implementation may set _intlMV_ to ~positive-infinity~. | |
1. If _intlMV_ is a mathematical value and _intlMV_ > ℝ(%Number.MAX_VALUE%), the implementation may set _intlMV_ to ~positive-infinity~. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not comfortable with the amount of variation this permits within and across implementations. Behavior should really be more predictable.
Do you have a counter proposal? Anything I can do to help align on the objective? |
Well, can we just remove all variance? - 1. If _intlMV_ is a mathematical value and _intlMV_ > ℝ(%Number.MAX_VALUE%), the implementation may set _intlMV_ to ~positive-infinity~.
- 1. If _intlMV_ is a mathematical value and _intlMV_ < ℝ(-%Number.MAX_VALUE%), the implementation may set _intlMV_ to ~negative-infinity~.
- 1. If _intlMV_ is a mathematical value and 0 < _intlMV_ < ℝ(%Number.MIN_VALUE%), the implementation may set _intlMV_ to 0.
- 1. If _intlMV_ is a mathematical value and 0 > _intlMV_ > ℝ(-%Number.MIN_VALUE%), the implementation may set _intlMV_ to ~negative-zero~.
+ 1. If _intlMV_ is a mathematical value and _intlMV_ > ℝ(%Number.MAX_VALUE%), set _intlMV_ to ~positive-infinity~.
+ 1. If _intlMV_ is a mathematical value and _intlMV_ < ℝ(-%Number.MAX_VALUE%), set _intlMV_ to ~negative-infinity~.
+ 1. If _intlMV_ is a mathematical value and 0 < _intlMV_ < ℝ(%Number.MIN_VALUE%), set _intlMV_ to 0.
+ 1. If _intlMV_ is a mathematical value and 0 > _intlMV_ > ℝ(-%Number.MIN_VALUE%), set _intlMV_ to ~negative-zero~. If not, then I think the best alternative is introducing symmetric implementation-defined bounds:
And in either case, I think it is also necessary to bound the precision of these values (e.g., implementations should be allowed—if not required—to treat |
Test262 -> tc39/test262#3772 |
@gibson042 The rationale for making soft lower bounds is
ECMA-402 requires all numbers to be rounded to a certain number of fraction or significant digits, not more than 20, so that already serves as a de-facto bound on the precision of these MVs. |
I'm saying that users are harmed by the same input being treated as infinite in one implementation but not in another. Why should this proposal not address that?
Implementers are strictly lower in the priority of constituencies than both authors and users. If V8 and/or ICU are failing to meet the needs of the latter groups, then we should push for fixes there (e.g., ICU exposing configuration of limits).
I believe you're referring to https://tc39.es/ecma262/multipage/overview.html#implementation-approximated , in which case I dispute the analogy because the difference between e.g. 253 and 253 + 1 is one of degree while the difference between e.g. 10**308 and Infinity is one of kind.
Hmm, that's true but it seems brittle. |
@anba How do you feel about this being a hard limit? |
I argue that the user harm is minimal. The primary motivation behind the Intl MV change was to support large, precise amounts of currency as required by amounts in bitcoin, yen, etc. Supporting more digits than a Number can represent was the pain point. I'm not aware of strong motivating use cases involving large power of 10 exponents.
While I agree with this in the general sense, when it comes to edge cases, I feel that implementors carry more weight. This change is motivated by implementation constraints that were discovered in Stage 3. I worry that a hard limit is trading one implementation constraint (internal limits on the size of the number) with another (having to interpret the size of the number).
Acknowledged
Why is it brittle? The effective requirement of implementations is that they support ~330 significant digits (~310 before the decimal separator and another ~20 after it for the largest valid value of maximumSignificantDigits). This is another edge case, and it's possible that we don't need so many digits, but any other number of digits is just an arbitrary choice, and it again treads into the territory of implementation challenge. |
Is there an easy way to compare a string which contains a number in decimal representation against This is the behaviour before NF v3: js> new Intl.NumberFormat("en", {minimumSignificantDigits: 1}).format(Number.MIN_VALUE)
"0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005"
js> Number.MIN_VALUE.toPrecision(100)
"4.940656458412465441765687928682213723650598026143247644255856825006755072702087518652998363616359924e-324"
js> new Intl.NumberFormat("en", {minimumSignificantDigits: 1}).format(Number.MIN_VALUE.toPrecision(100))
"0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005" When positive numbers smaller than I don't think we care too much about the behaviour of too small or too large values. What if we simply parse the input as a Number and when the result is ±Infinity, ± I think this could be expressed through the RoundMVResult operation:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the idea of rounding before compare against the limit.
…t limits. r=dminor Apply the Intl mathematical value limits from [1] to our code. The minimum and maximum exponents are now limited by `Number.MIN_VALUE` resp. `Number.MAX_VALUE`, which are both way below our previous limit of `9'999'999`. Also removes the BigInt exponent check, because `JS::BigInt::MaxDigitLength` already ensured that the maximum exponent has a reasonable value for BigInts. Updates the tests to ensure new limits are correctly applied. [1] tc39/proposal-intl-numberformat-v3#128 Differential Revision: https://phabricator.services.mozilla.com/D179942
Fixes #98
Replaces #117