The specification of the Decimal proposal and everything related to it, proposed to be added to ECMA-262 in new sections;
A list of amendments to be made to ECMA-402.
1 The Decimal128 Object
Introduction
Decimal128 values, as specified here, are intended to represent base-10 (decimal) numbers as specified in IEEE 754-2019 Decimal128. Only a subset of the values specified in IEEE 754-2019 Decimal128 are modeled here, namely, the set of canonicalized values, which can be intuitively understood as decimal numbers without trailing zeroes. A Decimal128 value, as specified here, is one of the following six kinds of values:
NaN𝔻, represending a decimal not-a-number
+∞𝔻, representing positive infinity as a decimal,
-∞𝔻, representing negative infinity as a decimal,
+0𝔻, represending non-negative zero as a decimal value
−0𝔻, representing negative zero as a decimal value, or
A Decimal128 value is said to be finite if it is either a mathematical value, +0𝔻 or -0𝔻. A zero Decimal128 value is one of +0𝔻 or -0𝔻. A finite non-zero Decimal128 value is a mathematical value satisfying the conditions listed above.
The mathematical value MV(x) of a finite Decimal128 value x is defined as follows:
Decimal128 values defined in this section are ECMAScript analogues of IEEE 754-2019 Decimal128 values. It is important to note that the full spectrum of values defined by IEEE 754-2019 Decimal128 are not available here, namely non-canonical Decimal128 values, which can be underdtood as values containing trailing zeroes. Also, this specification simplifies IEEE 754-2019 Decimal128 in a further way: there is only one Decimal128 value, NaN𝔻, representing all possible IEEE 754-2019 Decimal128 NaN values.
A Decimal128 rounding mode is one of the String values "ceil", "floor", "trunc", "halfExpand", and "halfEven". The default rounding mode is the String value "halfEven".
Table 1: Rounding modes in Decimal128 compared to IEEE 754-2019 rounding modes
The above five rounding modes are defined in IEEE 754-2019. This table is offered for implementors who may need to convert the Decimal128 rounding modes defined here into a library that may use the official IEEE 754-2019 rounding mode names. Additional rounding modes are used elsewhere in this specification, such as in Intl.NumberFormat.
For every non-NaN Decimal128 value, we define its sign as follows:
A finite non-zero Decimal128 value is normalized if its exponente satisfies 6144 ≥ e ≥ -6143. A finite non-zero Decimal128 value is denormalized if its exponente satisfies -6144 ≥ e ≥ -6176.
For a proper discussion of rounding, we need to separate how rounding occurs with normalized compared with denormlized values. For a normalized Decimal128 value we define its truncated exponent as equal to its exponent. For zero or denormalized Decimal128 values we define the truncated exponent as the constant -6143. Given this, we define the scaled significand of a finite Decimal128 value as follows:
The scaled significand of a zero Decimal128 value is 0.
The scaled significand of a non-zero Decimal128 value v is v × 1033 − te, where te is the truncated exponent of x.
Note 5
The scaled significand of a finite Decimal128 value is always an integer whose absolute value is less than 1034.
1.1 Abstract Operations
1.1.1 RoundToDecimal128Domain ( v [ , roundingMode ] )
The abstract operation RoundToDecimal128Domain takes argument v (a mathematical value) and optional argument roundingMode (a Decimal128 rounding mode) and returns +∞𝔻, -∞𝔻, +0𝔻, −0𝔻, or a mathematical value. It computes the closest approximation to a given mathematical value, rounded according to the given rounding mode, that is available within the limits of Decimal128. It performs the following steps when called:
If v = 0, return +0𝔻.
If v < 0, then
Let reverseRoundingMode be roundingMode.
If roundingMode is "floor", set reverseRoundingMode to "ceil".
If roundingMode is "ceil", set reverseRoundingMode to "floor".
1.1.1.1 ApplyRoundingModeToPositive ( m, roundingMode )
The abstract operation ApplyRoundingModeToPositive takes arguments m (a positive mathematical value) and roundingMode (a Decimal128 rounding mode) and returns an integer. It computes the closest integer approximation to a given positive mathematical value, rounded according to the given rounding mode. It performs the following steps when called:
The abstract operation Decimal128Abs takes argument argument (a Decimal128 value) and returns a Decimal128 value. It computes the absolute value of a Decimal128 value It performs the following steps when called:
The abstract operation Decimal128Negate takes argument argument (a Decimal128 value) and returns a Decimal128 value. It computes the negation of a Decimal128 value It performs the following steps when called:
If argument is NaN𝔻, return NaN𝔻.
If argument is +∞𝔻, return -∞𝔻.
If argument is -∞𝔻, return +∞𝔻.
If argument is +0𝔻, return −0𝔻.
If argument is −0𝔻, return +0𝔻.
Otherwise, return −argument.
1.1.4 CanonicalizeDecimalString ( digits )
The abstract operation CanonicalizeDecimalString takes argument digits (a String) and returns a String. It removes trailing zeroes, if any, from digits, which is assumed to be a string of digits, possibily followed by a "." and a non-empty sequence of digits. It performs the following steps when called:
If digits does not contain the substring".", return digits.
If the final code unit of digits is not the code unit 0x0030 (DIGIT ZERO), return digits.
Let lhs be the substring of digits up to the first occurrence of the string ".".
Let rhs be the substring of digits starting at the first code point after the first occurrence of the string ".".
Let noTrailingZeroes be the shortest substring of rhs that does not terminate with a sequence of the code point 0x0030 (DIGIT ZERO).
If noTrailingZeroes is "", return lhs.
Otherwise, return the concatenation of lhs, ".", and noTrailingZeroes.
1.1.5 Decimal128ToDecimalString ( argument )
The abstract operation Decimal128ToDecimalString takes argument argument (a Decimal128 value) and returns a String. It renders argument as a string in decimal notation, regardless of how many decimal digits would be required. It performs the following steps when called:
The abstract operation Decimal128ToExponentialString takes argument argument (a Decimal128 value) and returns a String. It renders argument in exponential notation. It performs the following steps when called:
Let coefficientStr be the unique decimal string representation of n without leading zeroes.
Let e be the unique integer for which 1 ≤ n × 10e < 10.
Let adjustedExp be -e.
Let adjustedExpStr be the unique decimal string representation of adjustedExp without leading zeroes.
Let firstDigit be the substring of coefficientStr from 0 to 1.
Let remainingDigits be the substring of coefficientStr starting at 1.
Return the concatenation of prefix, firstDigit, ".", remainingDigits, "e", and adjustedExpStr.
1.1.7 Decimal128ValueToObject ( argument )
The abstract operation Decimal128ValueToObject takes argument argument (a Decimal128 value) and returns a Decimal128 object. It converts a Decimal128 value to a Decimal128 object. It performs the following steps when called:
is the initial value of the the "Decimal128" property of the global object.
creates and initializes a new Decimal128 object when called as a constructor
may be used as the value of an extends clause of a class definition. Subclass constructors that intend to inherit the specified Decimal128 behaviour must include a super call to the Decimal128 constructor to create and initialize the subclass instance with a [[Decimal128Data]] internal slot.
1.2.1 Decimal128 ( x )
If NewTarget is undefined, throw a TypeError exception.
Given a Number argument, the constructor converts it to a String using the toString method (with no arguments). In some cases, this may not be desited. In some use cases, given a Number, one may wish to call the Decimal128 constructor not with the number but rather with, for instance, the result of calling toFixed or toPrecision on the Number, thereby ensuring a certain level of precision that may get lost when using Number’s toString.
This method returns a Number value represents the exponent, which is the integern for which the current Decimal128 object, v, there exists a mathematical values such that v = s × 10e and 1 ≤ abs(s) < 10. If the current Decimal128 object is infinite, it returns +∞. If the current Decimal128 object is a zero, it returns -∞.
This method returns a Decimal128 value representing the significand of the current Decimal128 object, which is the mathematical valuen for which the current Decimal128 object, v, there exists an integere such such that v = s × 10e and 1 ≤ abs(s) < 10. IF the current Decimal128 object is a zero, it returns a zero.
This operation follows the specification in Section 5.5.1 of IEEE 754-2019.
2.7 Decimal128.prototype.add ( x )
This method computes the addition of a Decimal128 object with another one. The computation proceeds as though infinite precision and unbounded range were available, rounding, if necessary.
This operation follows the specification in Section 5.4.1 of IEEE 754-2019.
2.8 Decimal128.prototype.subtract ( x )
This method computes subtracts the given Decimal128 object from the current one. The computation proceeds as though infinite precision and unbounded range were available, rounding, if necessary.
This operation follows the specification in Section 5.4.1 of IEEE 754-2019.
2.9 Decimal128.prototype.multiply ( x )
This method computes multiplies the current Decimal128 object by another one. The computation proceeds as though infinite precision and unbounded range were available, rounding, if necessary.
This operation follows the specification in Section 5.4.1 of IEEE 754-2019.
2.10 Decimal128.prototype.divide ( x )
This method computes divides the current Decimal128 object by another one. The computation proceeds as though infinite precision and unbounded range were available, rounding, if necessary.
This operation follows the specification in Section 5.4.1 of IEEE 754-2019.
2.11 Decimal128.prototype.remainder ( x )
This method computes the remainder upon dividing the current Decimal128 object by another one. The computation proceeds as though infinite precision and unbounded range were available, rounding, if necessary.
The remainder operation specified here deviates from the IEEE 754-2019 remainder operation (defined there in Section 5.3.1). We follow the the remainder operation for Number rather than IEEE 754, which specifies that, for example, the remainder 46 and 10 is -4 rather than 6.
2.12 Decimal128.prototype.compare ( x )
This method returns one of the four Number values -1𝔽, +0𝔽, 1𝔽, and NaN𝔽. It compares the mathematical value of the current Decimal128 object with that of another Decimal128 object.
This operation combines the compareQuietEqual, compareQuietLess operations in Section 5.6.1 (and explained in Section 5.11) of IEEE 754-2019.
2.13 Decimal128.prototype.equals ( x )
This method returns either true, false, or undefined according as the current Decimal128 object has the same mathematical value as the given Decimal128 object. The value undefined is returned if the current Decimal128 object or the argument is a NaN.
This operation corresponds to the compareQuietEqual operation in Section 5.6.1 (and explained in Section 5.11) of IEEE 754-2019.
2.14 Decimal128.prototype.notEquals ( x )
This method returns either true, false, or undefined according as the current Decimal128 object has a different mathematical value as the given Decimal128 object. The value undefined is returned if the current Decimal128 object or the argument is a NaN.
This operation corresponds to the compareQuietNotEqual operation in Section 5.6.1 (and explained in Section 5.11) of IEEE 754-2019.
2.15 Decimal128.prototype.lessThan ( x )
This method returns either true, false according as the current Decimal128 object has the same mathematical value as the given Decimal128 object. The value false is returned if the current Decimal128 object or the argument is a NaN.
This operation corresponds to the compareQuietEqual operation in Section 5.6.1 (and explained in Section 5.11) of IEEE 754-2019.
2.16 Decimal128.prototype.lessThanOrEqual ( x )
This method returns either true, false, or undefined according as the current Decimal128 object has the same or smaller mathematical value as the given Decimal128 object. The value false is returned if the current Decimal128 object or the argument is a NaN.
This operation corresponds to the compareQuietLessEqual operation in Section 5.6.1 (and explained in Section 5.11) of IEEE 754-2019.
2.17 Decimal128.prototype.greaterThan ( x )
This method returns either true, false according as the current Decimal128 object has a greater mathematical value as the given Decimal128 object. The value false is returned if either the current Decimal128 object or the argument is a NaN.
This operation corresponds to the compareQuietGreater operation in Section 5.6.1 (and explained in Section 5.11) of IEEE 754-2019.
2.18 Decimal128.prototype.greaterThanOrEqual ( x )
This method returns either true, false according as the current Decimal128 object has a greater or equal mathematical value as the given Decimal128 object. The value *false is returned if the current Decimal128 object or the argument is a NaN.
This method rounds the current Decimal128 object according to the specified rounding mode, which, if omitted, is the default rounding mode, with rounding taking place only after numFractionalDigits non-integer digits, which must be a non-negative integer Number.
This method generates a String representation of the current Decimal128 object, in decimal format. Its behaviour is similar to that of Number’s toString by rendering the decimal in decimal notation, but will use exponential notation if the the magnitude of the number is less than 10-6 or greater than 1034.
This operation follows the specification of the conversion of IEEE 754-2019 Decimal128 values to strings (external character sequences) discussed in Section 5.12 of IEEE 754-2019.
An ECMAScript implementation that includes the ECMA-402 Internationalization API must implement this method as specified in the ECMA-402 specification. If an ECMAScript implementation does not include the ECMA-402 API the following specification of this method is used:
This method produces a String value that represents this Decimal128 object formatted according to the conventions of the host environment’s current locale. This method is implementation-defined, and it is permissible, but not encouraged, for it to return the same thing as toString.
The meanings of the optional parameters to this method are defined in the ECMA-402 specification; implementations that do not include ECMA-402 support must not use those parameter positions for anything else.
This operation follows the specification of the conversion of IEEE 754-2019 Decimal128 values to strings (external character sequences) discussed in Section 5.12 of IEEE 754-2019.
2.24 Decimal128.prototype.toFixed ( [ options ] )
This method generates a String representation of the current Decimal128 object, in decimal format, with a specified number of digits after the decimal point.
Let s be the unique decimal string representation of roundedScaledV without leading zeroes.
Let integerDigits be s.
Let nonIntegerDigits be "".
If s contains an occurrence of ".", then
Let i be the index of the first occurrence of "." in s.
Set integerDigits to the substring of s from 0 to i.
Set nonIntegerDigits to the substring of s from i + 1.
If numDigits = 0, return integerDigits.
Let numNonIntegerDigits be the length of nonIntegerDigits.
If the numNonIntegerDigits < numDigits, then
Let additionalZeroes be the string "0" repeated numDigits - numNonIntegerDigits times.
Set nonIntegerDigits to the concatenation of nonIntegerDigits and additionalZeroes.
Else if numNonIntegerDigits > numDigits, then
Set nonIntegerDigits to the substring of nonIntegerDigits from 0 to numDigits.
Return the concatenation of signPrefix, integerDigits, ".", and nonIntegerDigits.
Note
This operation follows the specification of the conversion of IEEE 754-2019 Decimal128 values to strings (external character sequences) discussed in Section 5.12 of IEEE 754-2019.
2.25 Decimal128.prototype.toJSON ( )
It performs the following steps when called:
Throw a TypeError exception.
Note
The behaviour of this operation aligns with that of the conversion of BigInt values to JSON using JSON.stringify.
This method generates a String representation of the current Decimal128 object, in decimal format, with a specified number of significant digits. If the precision argument is omitted or is undefined, this method is equivalent to toString. This method may produce results in exponential notation or decimal notation.
Let adjustedMantissaStr be the unique decimal string representation of adjustedMantissa without leading zeroes and without trailing zeroes.
If e ≥ 0, set eStr to the concation of "+" and eStr.
Return the concation of signPrefix, adjustedMantissaStr, "e", and eStr.
Otherwise:
Let extraZeroes be the string "0" repeated numCoefficientDigits - 1 - numCoefficientDigits times.
Let s be the string concatenation of firstDigit, ".", remainingDigits, extraZeroes, "e", and eStr.
Return s.
Note
This operation follows the specification of the conversion of IEEE 754-2019 Decimal128 values to strings (external character sequences) discussed in Section 5.12 of IEEE 754-2019.
2.27 Decimal128.prototype.valueOf ( x )
This method performs the following steps when called:
Throw a TypeError exception.
3 Numbers and Dates
3.1 Number Objects
3.1.1 The Number Constructor
3.1.1.1 Number ( value )
This function performs the following steps when called:
If value is present, then
If value is an object that has an [[Decimal128Data]] internal slot, then
The abstract operation Decimal128ToBigInt takes argument number (an Object with a [[Decimal128Data]] internal slot) and returns either a normal completion containing a BigInt or a throw completion. It performs the following steps when called:
Let d be number.[[Decimal128Data]].
If d is NaN𝔻, +∞𝔻 or -∞𝔻, throw a RangeError exception.
4 Amendments to the ECMAScript® 2024 Internationalization API Specification
Editor's Note
This section lists amendments which must be made to ECMA-402, the ECMAScript® 2024 Internationalization API Specification.
Text to be added is marked like this, and text to be deleted is marked like this.
Blocks of unmodified text between modified sections are marked by [...].
4.2.1 Abstract Operations for NumberFormat Objects
4.2.1.1 ToIntlMathematicalValue ( value )
The abstract operation ToIntlMathematicalValue takes argument value (an ECMAScript language value) and returns either a normal completion containing an Intl mathematical value or a throw completion.
It returns value converted to an Intl mathematical value, which is either a mathematical value, or one of positive-infinity, negative-infinity, not-a-number, and negative-zero.
This abstract operation is similar to 7.1.3, but a mathematical value can be returned instead of a Number or BigInt, so that exact decimal values can be represented.
It performs the following steps when called:
If value has a [[Decimal128Data]] internal slot, then
If rounded is +∞𝔽 and intlMV < 0, return negative-infinity.
If rounded is +∞𝔽, return positive-infinity.
If rounded is +0𝔽 and intlMV < 0, return negative-zero.
If rounded is +0𝔽, return 0.
Return intlMV.
4.3 PluralRules Objects
4.3.1 Abstract Operations for PluralRules Objects
4.3.1.1 ResolvePlural ( pluralRules, n )
The abstract operation ResolvePlural takes arguments pluralRules (an Intl.PluralRules) and n (a Number or an Object with an [[Decimal128Data]] internal slot) and returns a Record with fields [[PluralCategory]] ("zero", "one", "two", "few", "many", or "other") and [[FormattedString]] (a String). The returned Record contains two string-valued fields describing n according to the effective locale and the options of pluralRules: [[PluralCategory]] characterizing its plural category, and [[FormattedString]] containing its formatted representation. It performs the following steps when called:
Return the Record { [[PluralCategory]]: p, [[FormattedString]]: s }.
4.3.1.2 ResolvePluralRange ( pluralRules, x, y )
The abstract operation ResolvePluralRange takes arguments pluralRules (an Intl.PluralRules), x (a Number or an Object with a [[Decimal128Data]] internal slot), and y (a Number or an Object with a [[Decimal128Data]] internal slot) and returns either a normal completion containing either "zero", "one", "two", "few", "many", or "other", or a throw completion. The returned String value represents the plural form of the range starting from x and ending at y according to the effective locale and the options of pluralRules. It performs the following steps when called:
If x is NaN or NaN𝔻 or y is NaNor NaN𝔻, throw a RangeError exception.
All Software contained in this document ("Software") is protected by copyright and is being made available under the "BSD License", included below. This Software may be subject to third party rights (rights from parties other than Ecma International), including patent rights, and no licenses under such third party rights are granted under this license even if the third party concerned is a member of Ecma International. SEE THE ECMA CODE OF CONDUCT IN PATENT MATTERS AVAILABLE AT https://ecma-international.org/memento/codeofconduct.htm FOR INFORMATION REGARDING THE LICENSING OF PATENT CLAIMS THAT ARE REQUIRED TO IMPLEMENT ECMA INTERNATIONAL STANDARDS.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
Neither the name of the authors nor Ecma International may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE ECMA INTERNATIONAL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ECMA INTERNATIONAL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.