Normative: Increase limits on Intl MV and explicitly limit significant digits#1022
Normative: Increase limits on Intl MV and explicitly limit significant digits#1022
Conversation
|
Just a note on the significant digits truncation: this could technically change the behavior of numbers so close to the edge of a rounding boundary where the discriminator is at a position less than -10000; for example, If this is a problem (it might not be: 10000 digits is beyond all known use cases), it can be fixed by performing a bigger refactoring of the spec in order to avoid the spec-required double rounding, but actually it is easier to implement if the truncation happens during parsing. |
|
Could someone confirm that this approach would not cause any issues with implementations that rely on ICU4C or ICU4J? |
|
ICU4C (and ICU4J) have a similar representation as ICU4X but use |
|
@erights It was suggested that we bring this PR to TG3. Could it be added to an upcoming TG3 agenda? |
|
Kris?
…On Thu, Aug 14, 2025 at 8:55 PM Shane F. Carr ***@***.***> wrote:
*sffc* left a comment (tc39/ecma402#1022)
<#1022 (comment)>
@erights <https://github.com/erights> It was suggested that we bring this
PR to TG3. Could it be added to an upcoming TG3 agenda?
—
Reply to this email directly, view it on GitHub
<#1022 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AACC3THL6LFDUYKUITH7ZGL3NVK4DAVCNFSM6AAAAACDPLFRVOVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZTCOJQGUZTGMBTHE>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
--
Cheers,
--MarkM
|
|
TG2 conditional approval; we will defer to TG1 on exactly what bounds to use: https://github.com/tc39/ecma402/blob/main/meetings/notes-2025-09-11.md#normative-increase-limits-on-intl-mv-and-explicitly-limit-significant-digits-1022 |
| 1. If _rounded_ is *+∞*<sub>𝔽</sub>, return ~positive-infinity~. | ||
| 1. If _rounded_ is *+0*<sub>𝔽</sub> and _intlMV_ < 0, return ~negative-zero~. | ||
| 1. If _rounded_ is *+0*<sub>𝔽</sub>, return 0. | ||
| 1. Let _e_ be the integer such that 10<sup>_e_</sup> ≤ abs(_intlMV_) < 10<sup>_e_ + 1</sup>. |
There was a problem hiding this comment.
Choosing such an e is impossible if intlMV is zero. To fix it, handle the zero case separately.
There was a problem hiding this comment.
| 1. Let _e_ be the integer such that 10<sup>_e_</sup> ≤ abs(_intlMV_) < 10<sup>_e_ + 1</sup>. | |
| 1. If _intlMV_ = 0, return 0. | |
| 1. Let _e_ be floor(log10(abs(_intlMV_))). |
|
The description above doesn't match what the algorithm is doing. I assume this is due to typos in the description? I don't see why 10e9999 would be in-bounds while 1e10000 would be out of bounds (it's the same mathematical value), which is what the description above is currently stating. The algorithm changes look good, once the bug when intlMV is zero is fixed. |
Use "1e10000" from <tc39/ecma402#1022> as the limit so we don't have to modify this test after the PR has been merged. Note: "1e309" is the smallest decimal string number outside the limits before that PR.
gibson042
left a comment
There was a problem hiding this comment.
See the below suggestions about how to dramatically simplify this algorithm.
But I agree with @waldemarhorwat about the description being inaccurate... it is not constraining significant digits as such but rather independently constraining whole digits and fractional digits each to a count of 10_000, such that larger whole parts support more total significant digits (e.g., a whole part of 0 implies at most 10_000 significant digits [all fractional] while a whole part of 12_345 is already 5 significant digits to which can be appended another 10_000 significant digits [all fractional] and a whole part of 1e10000 - 1 would already have 10_000 significant digits before even considering a fractional part).
I'm fine with this algorithm (ideally as an easier-to-comprehend simplification), but a constraint on significant digits would have a different definition and very different behavior (such behavior would in fact be like that of IEEE 754 numbers, losing precision near the top and bottom of the range).
| 1. If _rounded_ is *+∞*<sub>𝔽</sub>, return ~positive-infinity~. | ||
| 1. If _rounded_ is *+0*<sub>𝔽</sub> and _intlMV_ < 0, return ~negative-zero~. | ||
| 1. If _rounded_ is *+0*<sub>𝔽</sub>, return 0. | ||
| 1. Let _e_ be the integer such that 10<sup>_e_</sup> ≤ abs(_intlMV_) < 10<sup>_e_ + 1</sup>. |
There was a problem hiding this comment.
| 1. Let _e_ be the integer such that 10<sup>_e_</sup> ≤ abs(_intlMV_) < 10<sup>_e_ + 1</sup>. | |
| 1. If _intlMV_ = 0, return 0. | |
| 1. Let _e_ be floor(log10(abs(_intlMV_))). |
| 1. If _e_ ≥ 10000, then | ||
| 1. If _intlMV_ < 0, return ~negative-infinity~. | ||
| 1. Else, return ~positive-infinity~. | ||
| 1. If _e_ < -10000, then | ||
| 1. If _intlMV_ < 0, return ~negative-zero~. | ||
| 1. Else, return 0. |
There was a problem hiding this comment.
Aligning with tc39/ecma262#3733:
| 1. If _e_ ≥ 10000, then | |
| 1. If _intlMV_ < 0, return ~negative-infinity~. | |
| 1. Else, return ~positive-infinity~. | |
| 1. If _e_ < -10000, then | |
| 1. If _intlMV_ < 0, return ~negative-zero~. | |
| 1. Else, return 0. | |
| 1. If _e_ ≥ 10000, then | |
| 1. If _intlMV_ < 0, return ~negative-infinity~; else return ~positive-infinity~. | |
| 1. If _e_ < -10000, then | |
| 1. If _intlMV_ < 0, return ~negative-zero~; else return 0. |
| 1. Let _q_ be the largest integer such that _intlMV_ × 10<sup>-_q_</sup> is an integer. | ||
| 1. If _q_ < -10000, then | ||
| 1. Let _truncated_ be the largest mathematical value such that _truncated_ × 10<sup>10000</sup> is an integer and _truncated_ < abs(_intlMV_). | ||
| 1. If _intlMV_ < 0, return -_truncated_. | ||
| 1. Else, return _truncated_. |
There was a problem hiding this comment.
| 1. Let _q_ be the largest integer such that _intlMV_ × 10<sup>-_q_</sup> is an integer. | |
| 1. If _q_ < -10000, then | |
| 1. Let _truncated_ be the largest mathematical value such that _truncated_ × 10<sup>10000</sup> is an integer and _truncated_ < abs(_intlMV_). | |
| 1. If _intlMV_ < 0, return -_truncated_. | |
| 1. Else, return _truncated_. | |
| 1. Let _scaled_ be _intlMV_ × 10<sup>10000</sup>. | |
| 1. If _scaled_ is not an integer, then | |
| 1. Return truncate(_scaled_) / 10<sup>10000</sup>. |
This can also be generalized to subsume the preceding step:
1. If _e_ ≥ 10000, then
1. If _intlMV_ < 0, return ~negative-infinity~; else return ~positive-infinity~.
1. Let _scaled_ be _intlMV_ × 10<sup>10000</sup>.
1. If _scaled_ is not an integer, then
1. Let _truncated_ be truncate(_scaled_) / 10<sup>10000</sup>.
1. If _truncated_ = 0 and _intlMV_ < 0, return ~negative-zero~.
1. Return _truncated_.
See #1017
The intent of this PR is the following. In this table,
99~9stands in for 9999 digit 9s, and999~9stands in for 10000 digit 9s.