1 NumberFormat Objects

1.1 The Intl.NumberFormat Constructor

The NumberFormat constructor is the %NumberFormat% intrinsic object and a standard built-in property of the Intl object. Behaviour common to all service constructor properties of the Intl object is specified in .

1.1.1 Intl.NumberFormat ( [ locales [ , options ] ] )

When the Intl.NumberFormat function is called with optional arguments locales and options, the following steps are taken:

  1. If NewTarget is undefined, let newTarget be the active function object, else let newTarget be NewTarget.
  2. Let numberFormat be ? OrdinaryCreateFromConstructor(newTarget, "%NumberFormat.prototype%", « [[InitializedNumberFormat]], [[Locale]], [[DataLocale]], [[NumberingSystem]], [[Style]], [[Unit]], [[UnitDisplay]], [[Currency]], [[CurrencyDisplay]], [[CurrencySign]], [[MinimumIntegerDigits]], [[MinimumFractionDigits]], [[MaximumFractionDigits]], [[MinimumSignificantDigits]], [[MaximumSignificantDigits]], [[RoundingType]], [[Notation]], [[CompactDisplay]], [[UseGrouping]], [[SignDisplay]], [[RoundingMode]], [[RoundingIncrement]], [[TrailingZeroDisplay]], [[BoundFormat]] »).
  3. Perform ? InitializeNumberFormat(numberFormat, locales, options).
  4. If the implementation supports the normative optional constructor mode of , then
    1. Let this be the this value.
    2. Return ? ChainNumberFormat(numberFormat, NewTarget, this).
  5. Return numberFormat.

1.1.1.1 ChainNumberFormat ( numberFormat, newTarget, this )

  1. If newTarget is undefined and ? OrdinaryHasInstance(%NumberFormat%, this) is true, then
    1. Perform ? DefinePropertyOrThrow(this, %Intl%.[[FallbackSymbol]], PropertyDescriptor{ [[Value]]: numberFormat, [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }).
    2. Return this.
  2. Return numberFormat.

1.1.2 InitializeNumberFormat ( numberFormat, locales, options )

The abstract operation InitializeNumberFormat accepts the arguments numberFormat (which must be an object), locales, and options. It initializes numberFormat as a NumberFormat object. The following steps are taken:

The following algorithm refers to the type nonterminal from UTS 35's Unicode Locale Identifier grammar.

  1. Let requestedLocales be ? CanonicalizeLocaleList(locales).
  2. Set options to ? CoerceOptionsToObject(options).
  3. Let opt be a new Record.
  4. Let matcher be ? GetOption(options, "localeMatcher", string, « "lookup", "best fit" », "best fit").
  5. Set opt.[[localeMatcher]] to matcher.
  6. Let numberingSystem be ? GetOption(options, "numberingSystem", string, empty, undefined).
  7. If numberingSystem is not undefined, then
    1. If numberingSystem does not match the Unicode Locale Identifier type nonterminal, throw a RangeError exception.
  8. Set opt.[[nu]] to numberingSystem.
  9. Let localeData be %NumberFormat%.[[LocaleData]].
  10. Let r be ResolveLocale(%NumberFormat%.[[AvailableLocales]], requestedLocales, opt, %NumberFormat%.[[RelevantExtensionKeys]], localeData).
  11. Set numberFormat.[[Locale]] to r.[[locale]].
  12. Set numberFormat.[[DataLocale]] to r.[[dataLocale]].
  13. Set numberFormat.[[NumberingSystem]] to r.[[nu]].
  14. Perform ? SetNumberFormatUnitOptions(numberFormat, options).
  15. Let style be numberFormat.[[Style]].
  16. If style is "currency", then
    1. Let currency be numberFormat.[[Currency]].
    2. Let cDigits be CurrencyDigits(currency).
    3. Let mnfdDefault be cDigits.
    4. Let mxfdDefault be cDigits.
  17. Else,
    1. Let mnfdDefault be 0.
    2. If style is "percent", then
      1. Let mxfdDefault be 0.
    3. Else,
      1. Let mxfdDefault be 3.
  18. Let notation be ? GetOption(options, "notation", string, « "standard", "scientific", "engineering", "compact" », "standard").
  19. Set numberFormat.[[Notation]] to notation.
  20. Perform ? SetNumberFormatDigitOptions(numberFormat, options, mnfdDefault, mxfdDefault, notation).
  21. Let compactDisplay be ? GetOption(options, "compactDisplay", string, « "short", "long" », "short").
  22. Let defaultUseGrouping be "auto".
  23. If notation is "compact", then
    1. Set numberFormat.[[CompactDisplay]] to compactDisplay.
    2. Set defaultUseGrouping to "min2".
  24. NOTE: For historical reasons, the strings "true" and "false" are accepted and replaced with the default value.
  25. Let useGrouping be ? GetBooleanOrStringNumberFormatOption(options, "useGrouping", « "min2", "auto", "always", "true", "false" », defaultUseGrouping).
  26. If useGrouping is "true" or useGrouping is "false", set useGrouping to defaultUseGrouping.
  27. If useGrouping is true, set useGrouping to "always".
  28. Set numberFormat.[[UseGrouping]] to useGrouping.
  29. Let signDisplay be ? GetOption(options, "signDisplay", string, « "auto", "never", "always", "exceptZero", "negative" », "auto").
  30. Set numberFormat.[[SignDisplay]] to signDisplay.
  31. Return numberFormat.

1.1.3 SetNumberFormatDigitOptions ( intlObj, options, mnfdDefault, mxfdDefault, notation )

The abstract operation SetNumberFormatDigitOptions applies digit options used for number formatting onto the intl object. It is used by both Intl.NumberFormat and Intl.PluralRules.

  1. Let mnid be ? GetNumberOption(options, "minimumIntegerDigits,", 1, 21, 1).
  2. Let mnfd be ? Get(options, "minimumFractionDigits").
  3. Let mxfd be ? Get(options, "maximumFractionDigits").
  4. Let mnsd be ? Get(options, "minimumSignificantDigits").
  5. Let mxsd be ? Get(options, "maximumSignificantDigits").
  6. Set intlObj.[[MinimumIntegerDigits]] to mnid.
  7. Let roundingPriority be ? GetOption(options, "roundingPriority", string, « "auto", "morePrecision", "lessPrecision" », "auto").
  8. Let roundingIncrement be ? GetNumberOption(options, "roundingIncrement", 1, 5000, 1).
  9. If roundingIncrement is not in « 1, 2, 5, 10, 20, 25, 50, 100, 200, 250, 500, 1000, 2000, 2500, 5000 », throw a RangeError exception.
  10. Let roundingMode be ? GetOption(options, "roundingMode", string, « "ceil", "floor", "expand", "trunc", "halfCeil", "halfFloor", "halfExpand", "halfTrunc", "halfEven" », "halfExpand").
  11. Let trailingZeroDisplay be ? GetOption(options, "trailingZeroDisplay", string, « "auto", "stripIfInteger" », "auto").
  12. NOTE: All fields required by SetNumberFormatDigitOptions have now been read from options. The remainder of this AO interprets the options and may throw exceptions.
  13. If roundingIncrement is not 1, set mxfdDefault to mnfdDefault.
  14. Set intlObj.[[RoundingIncrement]] to roundingIncrement.
  15. Set intlObj.[[RoundingMode]] to roundingMode.
  16. Set intlObj.[[TrailingZeroDisplay]] to trailingZeroDisplay.
  17. If mnsd is not undefined or mxsd is not undefined, then
    1. Let hasSd be true.
  18. Else,
    1. Let hasSd be false.
  19. If mnfd is not undefined or mxfd is not undefined, then
    1. Let hasFd be true.
  20. Else,
    1. Let hasFd be false.
  21. Let needSd be true.
  22. Let needFd be true.
  23. If roundingPriority is "auto", then
    1. Set needSd to hasSd.
    2. If hasSd is true, or hasFd is false and notation is "compact", then
      1. Set needFd to false.
  24. If needSd is true, then
    1. If hasSd is true, then
      1. Set mnsd to ? DefaultNumberOption(mnsd, 1, 21, 1).
      2. Set mxsd to ? DefaultNumberOption(mxsd, mnsd, 21, 21).
      3. Set intlObj.[[MinimumSignificantDigits]] to mnsd.
      4. Set intlObj.[[MaximumSignificantDigits]] to mxsd.
    2. Else,
      1. Set intlObj.[[MinimumSignificantDigits]] to 1.
      2. Set intlObj.[[MaximumSignificantDigits]] to 21.
  25. If needFd is true, then
    1. If hasFd is true, then
      1. Set mnfd to ? DefaultNumberOption(mnfd, 0, 20, undefined).
      2. Set mxfd to ? DefaultNumberOption(mxfd, 0, 20, undefined).
      3. If mnfd is undefined, set mnfd to min(mnfdDefault, mxfd).
      4. Else if mxfd is undefined, set mxfd to max(mxfdDefault, mnfd).
      5. Else if mnfd is greater than mxfd, throw a RangeError exception.
      6. Set intlObj.[[MinimumFractionDigits]] to mnfd.
      7. Set intlObj.[[MaximumFractionDigits]] to mxfd.
    2. Else,
      1. Set intlObj.[[MinimumFractionDigits]] to mnfdDefault.
      2. Set intlObj.[[MaximumFractionDigits]] to mxfdDefault.
  26. If needSd is true or needFd is true, then
    1. If roundingPriority is "morePrecision", then
      1. Set intlObj.[[RoundingType]] to morePrecision.
    2. Else if roundingPriority is "lessPrecision", then
      1. Set intlObj.[[RoundingType]] to lessPrecision.
    3. Else if hasSd is true, then
      1. Set intlObj.[[RoundingType]] to significantDigits.
    4. Else,
      1. Set intlObj.[[RoundingType]] to fractionDigits.
  27. Else,
    1. Set intlObj.[[RoundingType]] to morePrecision.
    2. Set intlObj.[[MinimumFractionDigits]] to 0.
    3. Set intlObj.[[MaximumFractionDigits]] to 0.
    4. Set intlObj.[[MinimumSignificantDigits]] to 1.
    5. Set intlObj.[[MaximumSignificantDigits]] to 2.
  28. If roundingIncrement is not 1, then
    1. If intlObj.[[RoundingType]] is not fractionDigits, throw a TypeError exception.
    2. If intlObj.[[MaximumFractionDigits]] is not equal to intlObj.[[MinimumFractionDigits]], throw a RangeError exception.

1.1.4 SetNumberFormatUnitOptions ( intlObj, options )

The abstract operation SetNumberFormatUnitOptions resolves the user-specified options relating to units onto the intl object.

  1. Assert: Type(intlObj) is Object.
  2. Assert: Type(options) is Object.
  3. Let style be ? GetOption(options, "style", string, « "decimal", "percent", "currency", "unit" », "decimal").
  4. Set intlObj.[[Style]] to style.
  5. Let currency be ? GetOption(options, "currency", string, empty, undefined).
  6. If currency is undefined, then
    1. If style is "currency", throw a TypeError exception.
  7. Else,
    1. If the result of IsWellFormedCurrencyCode(currency) is false, throw a RangeError exception.
  8. Let currencyDisplay be ? GetOption(options, "currencyDisplay", string, « "code", "symbol", "narrowSymbol", "name" », "symbol").
  9. Let currencySign be ? GetOption(options, "currencySign", string, « "standard", "accounting" », "standard").
  10. Let unit be ? GetOption(options, "unit", string, empty, undefined).
  11. If unit is undefined, then
    1. If style is "unit", throw a TypeError exception.
  12. Else,
    1. If ! IsWellFormedUnitIdentifier(unit) is false, throw a RangeError exception.
  13. Let unitDisplay be ? GetOption(options, "unitDisplay", string, « "short", "narrow", "long" », "short").
  14. If style is "currency", then
    1. Set intlObj.[[Currency]] to the ASCII-uppercase of currency.
    2. Set intlObj.[[CurrencyDisplay]] to currencyDisplay.
    3. Set intlObj.[[CurrencySign]] to currencySign.
  15. If style is "unit", then
    1. Set intlObj.[[Unit]] to unit.
    2. Set intlObj.[[UnitDisplay]] to unitDisplay.

1.2 Properties of the Intl.NumberFormat Constructor

The Intl.NumberFormat constructor has the following properties:

1.2.1 Intl.NumberFormat.prototype

The value of Intl.NumberFormat.prototype is %NumberFormat.prototype%.

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }.

1.2.2 Intl.NumberFormat.supportedLocalesOf ( locales [ , options ] )

When the supportedLocalesOf method is called with arguments locales and options, the following steps are taken:

  1. Let availableLocales be %NumberFormat%.[[AvailableLocales]].
  2. Let requestedLocales be ? CanonicalizeLocaleList(locales).
  3. Return ? SupportedLocales(availableLocales, requestedLocales, options).

1.2.3 Internal slots

The value of the [[AvailableLocales]] internal slot is implementation-defined within the constraints described in .

The value of the [[RelevantExtensionKeys]] internal slot is « "nu" ».

Note 1
Unicode Technical Standard #35 describes three locale extension keys that are relevant to number formatting: "cu" for currency, "cf" for currency format style, and "nu" for numbering system. Intl.NumberFormat, however, requires that the currency of a currency format is specified through the currency property in the options objects, and the currency format style of a currency format is specified through the currencySign property in the options objects.

The value of the [[LocaleData]] internal slot is implementation-defined within the constraints described in and the following additional constraints:

  • The list that is the value of the "nu" field of any locale field of [[LocaleData]] must not include the values "native", "traditio", or "finance".
  • [[LocaleData]].[[<locale>]] must have a [[patterns]] field for all locale values locale. The value of this field must be a Record, which must have fields with the names of the four number format styles: "decimal", "percent", "currency", and "unit".
  • The two fields "currency" and "unit" noted above must be Records with at least one field, "fallback". The "currency" may have additional fields with keys corresponding to currency codes according to . Each field of "currency" must be a Record with fields corresponding to the possible currencyDisplay values: "code", "symbol", "narrowSymbol", and "name". Each of those fields must contain a Record with fields corresponding to the possible currencySign values: "standard" or "accounting". The "unit" field (of [[LocaleData]].[[<locale>]]) may have additional fields beyond the required field "fallback" with keys corresponding to core measurement unit identifiers corresponding to . Each field of "unit" must be a Record with fields corresponding to the possible unitDisplay values: "narrow", "short", and "long".
  • All of the leaf fields so far described for the patterns tree ("decimal", "percent", great-grandchildren of "currency", and grandchildren of "unit") must be Records with the keys "positivePattern", "zeroPattern", and "negativePattern".
  • The value of the aforementioned fields (the sign-dependent pattern fields) must be string values that must contain the substring "{number}". "positivePattern" must contain the substring "{plusSign}" but not "{minusSign}"; "negativePattern" must contain the substring "{minusSign}" but not "{plusSign}"; and "zeroPattern" must not contain either "{plusSign}" or "{minusSign}". Additionally, the values within the "percent" field must also contain the substring "{percentSign}"; the values within the "currency" field must also contain one or more of the following substrings: "{currencyCode}", "{currencyPrefix}", or "{currencySuffix}"; and the values within the "unit" field must also contain one or more of the following substrings: "{unitPrefix}" or "{unitSuffix}". The pattern strings, when interpreted as a sequence of UTF-16 encoded code points as described in es2023, , must not contain any code points in the General Category "Number, decimal digit" as specified by the Unicode Standard.
  • [[LocaleData]].[[<locale>]] must also have a [[notationSubPatterns]] field for all locale values locale. The value of this field must be a Record, which must have two fields: [[scientific]] and [[compact]]. The [[scientific]] field must be a string value containing the substrings "{number}", "{scientificSeparator}", and "{scientificExponent}". The [[compact]] field must be a Record with two fields: "short" and "long". Each of these fields must be a Record with integer keys corresponding to all discrete magnitudes the implementation supports for compact notation. Each of these fields must be a string value which may contain the substring "{number}". Strings descended from "short" must contain the substring "{compactSymbol}", and strings descended from "long" must contain the substring "{compactName}".
Note 2
It is recommended that implementations use the locale data provided by the Common Locale Data Repository (available at https://cldr.unicode.org/).

1.3 Properties of the Intl.NumberFormat Prototype Object

The Intl.NumberFormat prototype object is itself an ordinary object. %NumberFormat.prototype% is not an Intl.NumberFormat instance and does not have an [[InitializedNumberFormat]] internal slot or any of the other internal slots of Intl.NumberFormat instance objects.

1.3.1 Intl.NumberFormat.prototype.constructor

The initial value of Intl.NumberFormat.prototype.constructor is %NumberFormat%.

1.3.2 Intl.NumberFormat.prototype [ @@toStringTag ]

The initial value of the @@toStringTag property is the String value "Intl.NumberFormat".

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.

1.3.3 get Intl.NumberFormat.prototype.format

Intl.NumberFormat.prototype.format is an accessor property whose set accessor function is undefined. Its get accessor function performs the following steps:

  1. Let nf be the this value.
  2. If the implementation supports the normative optional constructor mode of , then
    1. Set nf to ? UnwrapNumberFormat(nf).
  3. Perform ? RequireInternalSlot(nf, [[InitializedNumberFormat]]).
  4. If nf.[[BoundFormat]] is undefined, then
    1. Let F be a new built-in function object as defined in Number Format Functions (1.5.2).
    2. Set F.[[NumberFormat]] to nf.
    3. Set nf.[[BoundFormat]] to F.
  5. Return nf.[[BoundFormat]].
Note
The returned function is bound to nf so that it can be passed directly to Array.prototype.map or other functions. This is considered a historical artefact, as part of a convention which is no longer followed for new features, but is preserved to maintain compatibility with existing programs.

1.3.4 Intl.NumberFormat.prototype.formatToParts ( value )

When the formatToParts method is called with an optional argument value, the following steps are taken:

  1. Let nf be the this value.
  2. Perform ? RequireInternalSlot(nf, [[InitializedNumberFormat]]).
  3. Let x be ? ToIntlMathematicalValue(value).
  4. Return ? FormatNumericToParts(nf, x).

1.3.5 Intl.NumberFormat.prototype.formatRange ( start, end )

When the formatRange method is called with arguments start and end, the following steps are taken:

  1. Let nf be the this value.
  2. Perform ? RequireInternalSlot(nf, [[InitializedNumberFormat]]).
  3. If start is undefined or end is undefined, throw a TypeError exception.
  4. Let x be ? ToIntlMathematicalValue(start).
  5. Let y be ? ToIntlMathematicalValue(end).
  6. Return ? FormatNumericRange(nf, x, y).

1.3.6 Intl.NumberFormat.prototype.formatRangeToParts ( start, end )

When the formatRangeToParts method is called with arguments start and end, the following steps are taken:

  1. Let nf be the this value.
  2. Perform ? RequireInternalSlot(nf, [[InitializedNumberFormat]]).
  3. If start is undefined or end is undefined, throw a TypeError exception.
  4. Let x be ? ToIntlMathematicalValue(start).
  5. Let y be ? ToIntlMathematicalValue(end).
  6. Return ? FormatNumericRangeToParts(nf, x, y).

1.3.7 Intl.NumberFormat.prototype.resolvedOptions ( )

This function provides access to the locale and options computed during initialization of the object.

  1. Let nf be the this value.
  2. If the implementation supports the normative optional constructor mode of , then
    1. Set nf to ? UnwrapNumberFormat(nf).
  3. Perform ? RequireInternalSlot(nf, [[InitializedNumberFormat]]).
  4. Let options be OrdinaryObjectCreate(%Object.prototype%).
  5. For each row of Table 1, except the header row, in table order, do
    1. Let p be the Property value of the current row.
    2. Let v be the value of nf's internal slot whose name is the Internal Slot value of the current row.
    3. If v is not undefined, then
      1. Perform ! CreateDataPropertyOrThrow(options, p, v).
  6. If nf.[[RoundingType]] is morePrecision, then
    1. Perform ! CreateDataPropertyOrThrow(options, "roundingPriority", "morePrecision").
  7. Else if nf.[[RoundingType]] is lessPrecision, then
    1. Perform ! CreateDataPropertyOrThrow(options, "roundingPriority", "lessPrecision").
  8. Else,
    1. Perform ! CreateDataPropertyOrThrow(options, "roundingPriority", "auto").
  9. Return options.
Table 1: Resolved Options of NumberFormat Instances
Internal Slot Property
[[Locale]] "locale"
[[NumberingSystem]] "numberingSystem"
[[Style]] "style"
[[Currency]] "currency"
[[CurrencyDisplay]] "currencyDisplay"
[[CurrencySign]] "currencySign"
[[Unit]] "unit"
[[UnitDisplay]] "unitDisplay"
[[MinimumIntegerDigits]] "minimumIntegerDigits"
[[MinimumFractionDigits]] "minimumFractionDigits"
[[MaximumFractionDigits]] "maximumFractionDigits"
[[MinimumSignificantDigits]] "minimumSignificantDigits"
[[MaximumSignificantDigits]] "maximumSignificantDigits"
[[UseGrouping]] "useGrouping"
[[Notation]] "notation"
[[CompactDisplay]] "compactDisplay"
[[SignDisplay]] "signDisplay"
[[RoundingMode]] "roundingMode"
[[RoundingIncrement]] "roundingIncrement"
[[TrailingZeroDisplay]] "trailingZeroDisplay"

1.4 Properties of Intl.NumberFormat Instances

Intl.NumberFormat instances are ordinary objects that inherit properties from %NumberFormat.prototype%.

Intl.NumberFormat instances have an [[InitializedNumberFormat]] internal slot.

Intl.NumberFormat instances also have several internal slots that are computed by the constructor:

  • [[Locale]] is a String value with the language tag of the locale whose localization is used for formatting.
  • [[DataLocale]] is a String value with the language tag of the nearest locale for which the implementation has data to perform the formatting operation. It will be a parent locale of [[Locale]].
  • [[NumberingSystem]] is a String value with the "type" given in Unicode Technical Standard #35 for the numbering system used for formatting.
  • [[Style]] is one of the String values "decimal", "currency", "percent", or "unit", identifying the type of quantity being measured.
  • [[Currency]] is a String value with the currency code identifying the currency to be used if formatting with the "currency" unit type. It is only used when [[Style]] has the value "currency".
  • [[CurrencyDisplay]] is one of the String values "code", "symbol", "narrowSymbol", or "name", specifying whether to display the currency as an ISO 4217 alphabetic currency code, a localized currency symbol, or a localized currency name if formatting with the "currency" style. It is only used when [[Style]] has the value "currency".
  • [[CurrencySign]] is one of the String values "standard" or "accounting", specifying whether to render negative numbers in accounting format, often signified by parenthesis. It is only used when [[Style]] has the value "currency" and when [[SignDisplay]] is not "never".
  • [[Unit]] is a core unit identifier. It is only used when [[Style]] has the value "unit".
  • [[UnitDisplay]] is one of the String values "short", "narrow", or "long", specifying whether to display the unit as a symbol, narrow symbol, or localized long name if formatting with the "unit" style. It is only used when [[Style]] has the value "unit".
  • [[MinimumIntegerDigits]] is a non-negative integer Number value indicating the minimum integer digits to be used. Numbers will be padded with leading zeroes if necessary.
  • [[MinimumFractionDigits]] and [[MaximumFractionDigits]] are non-negative integer Number values indicating the minimum and maximum fraction digits to be used. Numbers will be rounded or padded with trailing zeroes if necessary. These properties are only used when [[RoundingType]] is fractionDigits, morePrecision, or lessPrecision.
  • [[MinimumSignificantDigits]] and [[MaximumSignificantDigits]] are positive integer Number values indicating the minimum and maximum fraction digits to be shown. If present, the formatter uses however many fraction digits are required to display the specified number of significant digits. These properties are only used when [[RoundingType]] is significantDigits, morePrecision, or lessPrecision.
  • [[UseGrouping]] is a Boolean or String value indicating the conditions under which a grouping separator should be used. The positions of grouping separators, and whether to display grouping separators for a given number, is implementation-defined. A value "always" hints the implementation to display grouping separators if possible; "min2", if there are at least 2 digits in a group; "auto", if the locale prefers to use grouping separators for the number. A value false disables grouping separators.
  • [[RoundingType]] is one of the values fractionDigits, significantDigits, morePrecision, or lessPrecision, indicating which rounding strategy to use. If fractionDigits, the number is rounded according to [[MinimumFractionDigits]] and [[MaximumFractionDigits]], as described above. If significantDigits, the number is rounded according to [[MinimumSignificantDigits]] and [[MaximumSignificantDigits]] as described above. If morePrecision or lessPrecision, all four of those settings are used, with specific rules for disambiguating when to use one set versus the other. [[RoundingType]] is derived from the "roundingPriority" option and is converted back to "roundingPriority" in 1.3.7.
  • [[Notation]] is one of the String values "standard", "scientific", "engineering", or "compact", specifying whether the number should be displayed without scaling, scaled to the units place with the power of ten in scientific notation, scaled to the nearest thousand with the power of ten in scientific notation, or scaled to the nearest locale-dependent compact decimal notation power of ten with the corresponding compact decimal notation affix.
  • [[CompactDisplay]] is one of the String values "short" or "long", specifying whether to display compact notation affixes in short form ("5K") or long form ("5 thousand") if formatting with the "compact" notation. It is only used when [[Notation]] has the value "compact".
  • [[SignDisplay]] is one of the String values "auto", "always", "never", "exceptZero", or "negative", specifying when to include a sign (with non-"auto" options respectively corresponding with inclusion always, never, only for nonzero numbers, or only for nonzero negative numbers). In scientific notation, this slot affects the sign display of the mantissa but not the exponent.
  • [[RoundingMode]] is one of the String values in the Identifier column of Table 2, specifying which rounding mode to use.
  • [[RoundingIncrement]] is an integer-valued Number that evenly divides 10, 100, 1000, or 10000 into tenths, fifths, quarters, or halves. It indicates the increment at which rounding should take place relative to the calculated rounding magnitude. For example, if [[MaximumFractionDigits]] is 2 and [[RoundingIncrement]] is 5, then the number is rounded to the nearest 0.05 ("nickel rounding").
  • [[TrailingZeroDisplay]] is one of the String values "auto" or "stripIfInteger", indicating whether to strip trailing zeros if the formatted number is an integer (i.e., has no nonzero fraction digit).
Table 2: Rounding modes in Intl.NumberFormat
Identifier Description Examples: Round to 0 fraction digits
-1.5 0.4 0.5 0.6 1.5
"ceil" Toward positive infinity ➕ [-1] ➕ [1] ➕ [1] ➕ [1] ➕ [2]
"floor" Toward negative infinity ➖ [-2] ➖ [0] ➖ [0] ➖ [0] ➖ [1]
"expand" Away from zero ➖ [-2] ➕ [1] ➕ [1] ➕ [1] ➕ [2]
"trunc" Toward zero ➕ [-1] ➖ [0] ➖ [0] ➖ [0] ➖ [1]
"halfCeil" Ties toward positive infinity ➕ [-1] ➖ [0] ➕ [1] ➕ [1] ➕ [2]
"halfFloor" Ties toward negative infinity ➖ [-2] ➖ [0] ➖ [0] ➕ [1] ➖ [1]
"halfExpand" Ties away from zero ➖ [-2] ➖ [0] ➕ [1] ➕ [1] ➕ [2]
"halfTrunc" Ties toward zero ➕ [-1] ➖ [0] ➖ [0] ➕ [1] ➖ [1]
"halfEven" Ties toward even cardinality ➖ [-2] ➖ [0] ➖ [0] ➕ [1] ➕ [2]
Note
The examples are illustrative of the unique behavior of each option. ➕ means "resolves toward positive infinity"; ➖ means "resolves toward negative infinity".

Finally, Intl.NumberFormat instances have a [[BoundFormat]] internal slot that caches the function returned by the format accessor (1.3.3).

1.5 Abstract Operations for NumberFormat Objects

1.5.1 CurrencyDigits ( currency )

When the CurrencyDigits abstract operation is called with an argument currency (which must be an uppercase String value), the following steps are taken:

  1. If the ISO 4217 currency and funds code list contains currency as an alphabetic code, return the minor unit value corresponding to the currency from the list; otherwise, return 2.

1.5.2 Number Format Functions

A Number format function is an anonymous built-in function that has a [[NumberFormat]] internal slot.

When a Number format function F is called with optional argument value, the following steps are taken:

  1. Let nf be F.[[NumberFormat]].
  2. Assert: Type(nf) is Object and nf has an [[InitializedNumberFormat]] internal slot.
  3. If value is not provided, let value be undefined.
  4. Let x be ? ToIntlMathematicalValue(value).
  5. Return ? FormatNumeric(nf, x).

The "length" property of a Number format function is 1.

1.5.3 FormatNumericToString ( intlObject, x )

The FormatNumericToString abstract operation is called with arguments intlObject (which must be an object with [[RoundingMode]], [[RoundingType]], [[MinimumSignificantDigits]], [[MaximumSignificantDigits]], [[MinimumIntegerDigits]], [[MinimumFractionDigits]], [[MaximumFractionDigits]], [[RoundingIncrement]], and [[TrailingZeroDisplay]] internal slots), and x (which must be a mathematical value or negative-zero). It rounds x to an Intl mathematical value according to the internal slots of intlObject and returns a Record with a [[RoundedNumber]] field containing containing that result and a [[FormattedString]] field containing a String value representation of that result formatted according to the internal slots of intlObject.

  1. If x is negative-zero, then
    1. Let isNegative be true.
    2. Set x to 0.
  2. Else,
    1. Assert: x is a mathematical value.
    2. If x < 0, let isNegative be true; else let isNegative be false.
    3. If isNegative is true, then
      1. Set x to -x.
  3. Let unsignedRoundingMode be GetUnsignedRoundingMode(intlObject.[[RoundingMode]], isNegative).
  4. If intlObject.[[RoundingType]] is significantDigits, then
    1. Let result be ToRawPrecision(x, intlObject.[[MinimumSignificantDigits]], intlObject.[[MaximumSignificantDigits]], unsignedRoundingMode).
  5. Else if intlObject.[[RoundingType]] is fractionDigits, then
    1. Let result be ToRawFixed(x, intlObject.[[MinimumFractionDigits]], intlObject.[[MaximumFractionDigits]], intlObject.[[RoundingIncrement]], unsignedRoundingMode).
  6. Else,
    1. Let sResult be ToRawPrecision(x, intlObject.[[MinimumSignificantDigits]], intlObject.[[MaximumSignificantDigits]], unsignedRoundingMode).
    2. Let fResult be ToRawFixed(x, intlObject.[[MinimumFractionDigits]], intlObject.[[MaximumFractionDigits]], intlObject.[[RoundingIncrement]], unsignedRoundingMode).
    3. If intlObj.[[RoundingType]] is morePrecision, then
      1. If sResult.[[RoundingMagnitude]] ≤ fResult.[[RoundingMagnitude]], then
        1. Let result be sResult.
      2. Else,
        1. Let result be fResult.
    4. Else,
      1. Assert: intlObj.[[RoundingType]] is lessPrecision.
      2. If sResult.[[RoundingMagnitude]] ≤ fResult.[[RoundingMagnitude]], then
        1. Let result be fResult.
      3. Else,
        1. Let result be sResult.
  7. Set x to result.[[RoundedNumber]].
  8. Let string be result.[[FormattedString]].
  9. If intlObject.[[TrailingZeroDisplay]] is "stripIfInteger" and x modulo 1 = 0, then
    1. Let i be StringIndexOf(string, ".", 0).
    2. If i ≠ -1, set string to the substring of string from 0 to i.
  10. Let int be result.[[IntegerDigitsCount]].
  11. Let minInteger be intlObject.[[MinimumIntegerDigits]].
  12. If int < minInteger, then
    1. Let forwardZeros be the String consisting of minInteger - int occurrences of the code unit 0x0030 (DIGIT ZERO).
    2. Set string to the string-concatenation of forwardZeros and string.
  13. If isNegative is true, then
    1. If x is 0, set x to negative-zero. Otherwise, set x to -x.
  14. Return the Record { [[RoundedNumber]]: x, [[FormattedString]]: string }.

1.5.4 PartitionNumberPattern ( numberFormat, x )

takes arguments numberFormat (an object initialized as a NumberFormat) and x (an Intl mathematical value). It creates the parts representing the mathematical value of x according to the effective locale and the formatting options of numberFormat. It performs the following steps when called:

  1. Let exponent be 0.
  2. If x is not-a-number, then
    1. Let n be an implementation- and locale-dependent (ILD) String value indicating the NaN value.
  3. Else if x is positive-infinity, then
    1. Let n be an ILD String value indicating positive infinity.
  4. Else if x is negative-infinity, then
    1. Let n be an ILD String value indicating negative infinity.
  5. Else,
    1. If x is not negative-zero,
      1. Assert: x is a mathematical value.
      2. If numberFormat.[[Style]] is "percent", set x be 100 × x.
      3. Let exponent be ComputeExponent(numberFormat, x).
      4. Set x to x × 10-exponent.
    2. Let formatNumberResult be FormatNumericToString(numberFormat, x).
    3. Let n be formatNumberResult.[[FormattedString]].
    4. Set x to formatNumberResult.[[RoundedNumber]].
  6. Let pattern be GetNumberFormatPattern(numberFormat, x).
  7. Let result be a new empty List.
  8. Let patternParts be PartitionPattern(pattern).
  9. For each Record { [[Type]], [[Value]] } patternPart of patternParts, do
    1. Let p be patternPart.[[Type]].
    2. If p is "literal", then
      1. Append a new Record { [[Type]]: "literal", [[Value]]: patternPart.[[Value]] } as the last element of result.
    3. Else if p is equal to "number", then
      1. Let notationSubParts be PartitionNotationSubPattern(numberFormat, x, n, exponent).
      2. Append all elements of notationSubParts to result.
    4. Else if p is equal to "plusSign", then
      1. Let plusSignSymbol be the ILND String representing the plus sign.
      2. Append a new Record { [[Type]]: "plusSign", [[Value]]: plusSignSymbol } as the last element of result.
    5. Else if p is equal to "minusSign", then
      1. Let minusSignSymbol be the ILND String representing the minus sign.
      2. Append a new Record { [[Type]]: "minusSign", [[Value]]: minusSignSymbol } as the last element of result.
    6. Else if p is equal to "percentSign" and numberFormat.[[Style]] is "percent", then
      1. Let percentSignSymbol be the ILND String representing the percent sign.
      2. Append a new Record { [[Type]]: "percentSign", [[Value]]: percentSignSymbol } as the last element of result.
    7. Else if p is equal to "unitPrefix" and numberFormat.[[Style]] is "unit", then
      1. Let unit be numberFormat.[[Unit]].
      2. Let unitDisplay be numberFormat.[[UnitDisplay]].
      3. Let mu be an ILD String value representing unit before x in unitDisplay form, which may depend on x in languages having different plural forms.
      4. Append a new Record { [[Type]]: "unit", [[Value]]: mu } as the last element of result.
    8. Else if p is equal to "unitSuffix" and numberFormat.[[Style]] is "unit", then
      1. Let unit be numberFormat.[[Unit]].
      2. Let unitDisplay be numberFormat.[[UnitDisplay]].
      3. Let mu be an ILD String value representing unit after x in unitDisplay form, which may depend on x in languages having different plural forms.
      4. Append a new Record { [[Type]]: "unit", [[Value]]: mu } as the last element of result.
    9. Else if p is equal to "currencyCode" and numberFormat.[[Style]] is "currency", then
      1. Let currency be numberFormat.[[Currency]].
      2. Let cd be currency.
      3. Append a new Record { [[Type]]: "currency", [[Value]]: cd } as the last element of result.
    10. Else if p is equal to "currencyPrefix" and numberFormat.[[Style]] is "currency", then
      1. Let currency be numberFormat.[[Currency]].
      2. Let currencyDisplay be numberFormat.[[CurrencyDisplay]].
      3. Let cd be an ILD String value representing currency before x in currencyDisplay form, which may depend on x in languages having different plural forms.
      4. Append a new Record { [[Type]]: "currency", [[Value]]: cd } as the last element of result.
    11. Else if p is equal to "currencySuffix" and numberFormat.[[Style]] is "currency", then
      1. Let currency be numberFormat.[[Currency]].
      2. Let currencyDisplay be numberFormat.[[CurrencyDisplay]].
      3. Let cd be an ILD String value representing currency after x in currencyDisplay form, which may depend on x in languages having different plural forms. If the implementation does not have such a representation of currency, use currency itself.
      4. Append a new Record { [[Type]]: "currency", [[Value]]: cd } as the last element of result.
    12. Else,
      1. Let unknown be an ILND String based on x and p.
      2. Append a new Record { [[Type]]: "unknown", [[Value]]: unknown } as the last element of result.
  10. Return result.

1.5.5 PartitionNotationSubPattern ( numberFormat, x, n, exponent )

The PartitionNotationSubPattern abstract operation is called with arguments numberFormat (which must be an object initialized as a NumberFormat), x (which is an Intl mathematical value after rounding is applied), n (which is an intermediate formatted string), and exponent (an integer), and creates the corresponding parts for the number and notation according to the effective locale and the formatting options of numberFormat. The following steps are taken:

  1. Let result be a new empty List.
  2. If x is not-a-number, then
    1. Append a new Record { [[Type]]: "nan", [[Value]]: n } as the last element of result.
  3. Else if x is positive-infinity or negative-infinity, then
    1. Append a new Record { [[Type]]: "infinity", [[Value]]: n } as the last element of result.
  4. Else,
    1. Let notationSubPattern be GetNotationSubPattern(numberFormat, exponent).
    2. Let patternParts be PartitionPattern(notationSubPattern).
    3. For each Record { [[Type]], [[Value]] } patternPart of patternParts, do
      1. Let p be patternPart.[[Type]].
      2. If p is "literal", then
        1. Append a new Record { [[Type]]: "literal", [[Value]]: patternPart.[[Value]] } as the last element of result.
      3. Else if p is equal to "number", then
        1. If the numberFormat.[[NumberingSystem]] matches one of the values in the "Numbering System" column of Table 3 below, then
          1. Let digits be a List whose elements are the code points specified in the "Digits" column of the matching row in Table 3.
          2. Assert: The length of digits is 10.
          3. Let transliterated be the empty String.
          4. Let len be the length of n.
          5. Let position be 0.
          6. Repeat, while position < len,
            1. Let c be the code unit at index position within n.
            2. If 0x0030 ≤ c ≤ 0x0039, then
              1. NOTE: c is an ASCII digit.
              2. Let i be c - 0x0030.
              3. Set c to CodePointsToString(« digits[i] »).
            3. Set transliterated to the string-concatenation of transliterated and c.
            4. Set position to position + 1.
          7. Set n to transliterated.
        2. Else use an implementation dependent algorithm to map n to the appropriate representation of n in the given numbering system.
        3. Let decimalSepIndex be StringIndexOf(n, ".", 0).
        4. If decimalSepIndex > 0, then
          1. Let integer be the substring of n from position 0, inclusive, to position decimalSepIndex, exclusive.
          2. Let fraction be the substring of n from position decimalSepIndex, exclusive, to the end of n.
        5. Else,
          1. Let integer be n.
          2. Let fraction be undefined.
        6. If the numberFormat.[[UseGrouping]] is false, then
          1. Append a new Record { [[Type]]: "integer", [[Value]]: integer } as the last element of result.
        7. Else,
          1. Let groupSepSymbol be the implementation-, locale-, and numbering system-dependent (ILND) String representing the grouping separator.
          2. Let groups be a List whose elements are, in left to right order, the substrings defined by ILND set of locations within the integer, which may depend on the value of numberFormat.[[UseGrouping]].
          3. Assert: The number of elements in groups List is greater than 0.
          4. Repeat, while groups List is not empty,
            1. Remove the first element from groups and let integerGroup be the value of that element.
            2. Append a new Record { [[Type]]: "integer", [[Value]]: integerGroup } as the last element of result.
            3. If groups List is not empty, then
              1. Append a new Record { [[Type]]: "group", [[Value]]: groupSepSymbol } as the last element of result.
        8. If fraction is not undefined, then
          1. Let decimalSepSymbol be the ILND String representing the decimal separator.
          2. Append a new Record { [[Type]]: "decimal", [[Value]]: decimalSepSymbol } as the last element of result.
          3. Append a new Record { [[Type]]: "fraction", [[Value]]: fraction } as the last element of result.
      4. Else if p is equal to "compactSymbol", then
        1. Let compactSymbol be an ILD string representing exponent in short form, which may depend on x in languages having different plural forms. The implementation must be able to provide this string, or else the pattern would not have a "{compactSymbol}" placeholder.
        2. Append a new Record { [[Type]]: "compact", [[Value]]: compactSymbol } as the last element of result.
      5. Else if p is equal to "compactName", then
        1. Let compactName be an ILD string representing exponent in long form, which may depend on x in languages having different plural forms. The implementation must be able to provide this string, or else the pattern would not have a "{compactName}" placeholder.
        2. Append a new Record { [[Type]]: "compact", [[Value]]: compactName } as the last element of result.
      6. Else if p is equal to "scientificSeparator", then
        1. Let scientificSeparator be the ILND String representing the exponent separator.
        2. Append a new Record { [[Type]]: "exponentSeparator", [[Value]]: scientificSeparator } as the last element of result.
      7. Else if p is equal to "scientificExponent", then
        1. If exponent < 0, then
          1. Let minusSignSymbol be the ILND String representing the minus sign.
          2. Append a new Record { [[Type]]: "exponentMinusSign", [[Value]]: minusSignSymbol } as the last element of result.
          3. Let exponent be -exponent.
        2. Let exponentResult be ToRawFixed(exponent, 0, 0, 1, undefined).
        3. Append a new Record { [[Type]]: "exponentInteger", [[Value]]: exponentResult.[[FormattedString]] } as the last element of result.
      8. Else,
        1. Let unknown be an ILND String based on x and p.
        2. Append a new Record { [[Type]]: "unknown", [[Value]]: unknown } as the last element of result.
  5. Return result.
Table 3: Numbering systems with simple digit mappings
Numbering System Digits
adlm U+1E950 to U+1E959
ahom U+11730 to U+11739
arab U+0660 to U+0669
arabext U+06F0 to U+06F9
bali U+1B50 to U+1B59
beng U+09E6 to U+09EF
bhks U+11C50 to U+11C59
brah U+11066 to U+1106F
cakm U+11136 to U+1113F
cham U+AA50 to U+AA59
deva U+0966 to U+096F
diak U+11950 to U+11959
fullwide U+FF10 to U+FF19
gong U+11DA0 to U+11DA9
gonm U+11D50 to U+11D59
gujr U+0AE6 to U+0AEF
guru U+0A66 to U+0A6F
hanidec U+3007, U+4E00, U+4E8C, U+4E09, U+56DB, U+4E94, U+516D, U+4E03, U+516B, U+4E5D
hmng U+16B50 to U+16B59
hmnp U+1E140 to U+1E149
java U+A9D0 to U+A9D9
kali U+A900 to U+A909
khmr U+17E0 to U+17E9
knda U+0CE6 to U+0CEF
lana U+1A80 to U+1A89
lanatham U+1A90 to U+1A99
laoo U+0ED0 to U+0ED9
latn U+0030 to U+0039
lepc U+1C40 to U+1C49
limb U+1946 to U+194F
mathbold U+1D7CE to U+1D7D7
mathdbl U+1D7D8 to U+1D7E1
mathmono U+1D7F6 to U+1D7FF
mathsanb U+1D7EC to U+1D7F5
mathsans U+1D7E2 to U+1D7EB
mlym U+0D66 to U+0D6F
modi U+11650 to U+11659
mong U+1810 to U+1819
mroo U+16A60 to U+16A69
mtei U+ABF0 to U+ABF9
mymr U+1040 to U+1049
mymrshan U+1090 to U+1099
mymrtlng U+A9F0 to U+A9F9
newa U+11450 to U+11459
nkoo U+07C0 to U+07C9
olck U+1C50 to U+1C59
orya U+0B66 to U+0B6F
osma U+104A0 to U+104A9
rohg U+10D30 to U+10D39
saur U+A8D0 to U+A8D9
segment U+1FBF0 to U+1FBF9
shrd U+111D0 to U+111D9
sind U+112F0 to U+112F9
sinh U+0DE6 to U+0DEF
sora U+110F0 to U+110F9
sund U+1BB0 to U+1BB9
takr U+116C0 to U+116C9
talu U+19D0 to U+19D9
tamldec U+0BE6 to U+0BEF
telu U+0C66 to U+0C6F
thai U+0E50 to U+0E59
tibt U+0F20 to U+0F29
tirh U+114D0 to U+114D9
tnsa U+16AC0 to U+16AC9
vaii U+A620 to U+A629
wara U+118E0 to U+118E9
wcho U+1E2F0 to U+1E2F9
Note 1
The computations rely on String values and locations within numeric strings that are dependent upon the implementation and the effective locale of numberFormat ("ILD") or upon the implementation, the effective locale, and the numbering system of numberFormat ("ILND"). The ILD and ILND Strings mentioned, other than those for currency names, must not contain any code points in the General Category "Number, decimal digit" as specified by the Unicode Standard.
Note 2
It is recommended that implementations use the locale provided by the Common Locale Data Repository (available at https://cldr.unicode.org/).

1.5.6 FormatNumeric ( numberFormat, x )

The FormatNumeric abstract operation is called with arguments numberFormat (which must be an object initialized as a NumberFormat) and x (which must be an Intl mathematical value), and performs the following steps:

  1. Let parts be ? PartitionNumberPattern(numberFormat, x).
  2. Let result be the empty String.
  3. For each Record { [[Type]], [[Value]] } part in parts, do
    1. Set result to the string-concatenation of result and part.[[Value]].
  4. Return result.

1.5.7 FormatNumericToParts ( numberFormat, x )

The FormatNumericToParts abstract operation is called with arguments numberFormat (which must be an object initialized as a NumberFormat) and x (which must be an Intl mathematical value), and performs the following steps:

  1. Let parts be ? PartitionNumberPattern(numberFormat, x).
  2. Let result be ! ArrayCreate(0).
  3. Let n be 0.
  4. For each Record { [[Type]], [[Value]] } part in parts, do
    1. Let O be OrdinaryObjectCreate(%Object.prototype%).
    2. Perform ! CreateDataPropertyOrThrow(O, "type", part.[[Type]]).
    3. Perform ! CreateDataPropertyOrThrow(O, "value", part.[[Value]]).
    4. Perform ! CreateDataPropertyOrThrow(result, ! ToString(n), O).
    5. Increment n by 1.
  5. Return result.

1.5.8 ToRawPrecision ( x, minPrecision, maxPrecision, unsignedRoundingMode )

ToRawPrecision is an abstract operation that involves solving the following equation, which returns a valid mathematical value given integer inputs:

ToRawPrecisionFn(n, e, p) = n × 10ep+1
where 10p–1n < 10p

When the ToRawPrecision abstract operation is called with arguments x (which must be a finite non-negative mathematical value), minPrecision, maxPrecision (both must be integers between 1 and 21), and unsignedRoundingMode (a specification type from the Unsigned Rounding Mode column of Table 4 or undefined), the following steps are taken:

  1. Let p be maxPrecision.
  2. If x = 0, then
    1. Let m be the String consisting of p occurrences of the code unit 0x0030 (DIGIT ZERO).
    2. Let e be 0.
    3. Let xFinal be 0.
  3. Else,
    1. Let n1 and e1 each be an integer and r1 a mathematical value, with r1 = ToRawPrecisionFn(n1, e1, p), such that r1x and r1 is maximized.
    2. Let n2 and e2 each be an integer and r2 a mathematical value, with r2 = ToRawPrecisionFn(n2, e2, p), such that r2x and r2 is minimized.
    3. Let r be ApplyUnsignedRoundingMode(x, r1, r2, unsignedRoundingMode).
    4. If r is r1, then
      1. Let n be n1.
      2. Let e be e1.
      3. Let xFinal be r1.
    5. Else,
      1. Let n be n2.
      2. Let e be e2.
      3. Let xFinal be r2.
    6. Let m be the String consisting of the digits of the decimal representation of n (in order, with no leading zeroes).
  4. If e ≥ (p - 1), then
    1. Set m to the string-concatenation of m and e - p + 1 occurrences of the code unit 0x0030 (DIGIT ZERO).
    2. Let int be e + 1.
  5. Else if e ≥ 0, then
    1. Set m to the string-concatenation of the first e + 1 code units of m, the code unit 0x002E (FULL STOP), and the remaining p - (e + 1) code units of m.
    2. Let int be e + 1.
  6. Else,
    1. Assert: e < 0.
    2. Set m to the string-concatenation of "0.", -(e + 1) occurrences of the code unit 0x0030 (DIGIT ZERO), and m.
    3. Let int be 1.
  7. If m contains the code unit 0x002E (FULL STOP) and maxPrecision > minPrecision, then
    1. Let cut be maxPrecision - minPrecision.
    2. Repeat, while cut > 0 and the last code unit of m is 0x0030 (DIGIT ZERO),
      1. Remove the last code unit from m.
      2. Decrease cut by 1.
    3. If the last code unit of m is 0x002E (FULL STOP), then
      1. Remove the last code unit from m.
  8. Return the Record { [[FormattedString]]: m, [[RoundedNumber]]: xFinal, [[IntegerDigitsCount]]: int, [[RoundingMagnitude]]: ep+1 }.

1.5.9 ToRawFixed ( x, minFraction, maxFraction, roundingIncrement, unsignedRoundingMode )

ToRawFixed is an abstract operation that involves solving the following equation, which returns a valid mathematical value given integer inputs:

ToRawFixedFn(n, f) = n × 10f

When the ToRawFixed abstract operation is called with arguments x (which must be a finite non-negative mathematical value), minFraction, maxFraction (which must be integers between 0 and 20), roundingIncrement (an integer), and unsignedRoundingMode (a specification type from the Unsigned Rounding Mode column of Table 4 or undefined), the following steps are taken:

  1. Let f be maxFraction.
  2. Let n1 be an integer and r1 a mathematical value, with r1 = ToRawFixedFn(n1, f), such that n1 modulo roundingIncrement = 0, r1x, and r1 is maximized.
  3. Let n2 be an integer and r2 a mathematical value, with r2 = ToRawFixedFn(n2, f), such that n2 modulo roundingIncrement = 0, r2x, and r2 is minimized.
  4. Let r be ApplyUnsignedRoundingMode(x, r1, r2, unsignedRoundingMode).
  5. If r is r1, then
    1. Let n be n1.
    2. Let xFinal be r1.
  6. Else,
    1. Let n be n2.
    2. Let xFinal be r2.
  7. If n = 0, let m be "0". Otherwise, let m be the String consisting of the digits of the decimal representation of n (in order, with no leading zeroes).
  8. If f ≠ 0, then
    1. Let k be the length of m.
    2. If kf, then
      1. Let z be the String value consisting of f + 1 - k occurrences of the code unit 0x0030 (DIGIT ZERO).
      2. Set m to the string-concatenation of z and m.
      3. Set k to f + 1.
    3. Let a be the first k - f code units of m, and let b be the remaining f code units of m.
    4. Set m to the string-concatenation of a, ".", and b.
    5. Let int be the length of a.
  9. Else, let int be the length of m.
  10. Let cut be maxFraction - minFraction.
  11. Repeat, while cut > 0 and the last code unit of m is 0x0030 (DIGIT ZERO),
    1. Remove the last code unit from m.
    2. Decrease cut by 1.
  12. If the last code unit of m is 0x002E (FULL STOP), then
    1. Remove the last code unit from m.
  13. Return the Record { [[FormattedString]]: m, [[RoundedNumber]]: xFinal, [[IntegerDigitsCount]]: int, [[RoundingMagnitude]]: –f }.

1.5.10 UnwrapNumberFormat ( nf )

The UnwrapNumberFormat abstract operation returns the NumberFormat instance of its input object, which is either the value itself or a value associated with it by %NumberFormat% according to the normative optional constructor mode of .

  1. If Type(nf) is not Object, throw a TypeError exception.
  2. If nf does not have an [[InitializedNumberFormat]] internal slot and ? OrdinaryHasInstance(%NumberFormat%, nf) is true, then
    1. Return ? Get(nf, %Intl%.[[FallbackSymbol]]).
  3. Return nf.

1.5.11 GetNumberFormatPattern ( numberFormat, x )

The abstract operation GetNumberFormatPattern considers the resolved unit-related options in the number format object along with the final scaled and rounded number being formatted (an Intl mathematical value) and returns a pattern, a String value as described in 1.2.3.

  1. Let localeData be %NumberFormat%.[[LocaleData]].
  2. Let dataLocale be numberFormat.[[DataLocale]].
  3. Let dataLocaleData be localeData.[[<dataLocale>]].
  4. Let patterns be dataLocaleData.[[patterns]].
  5. Assert: patterns is a Record (see 1.2.3).
  6. Let style be numberFormat.[[Style]].
  7. If style is "percent", then
    1. Let patterns be patterns.[[percent]].
  8. Else if style is "unit", then
    1. Let unit be numberFormat.[[Unit]].
    2. Let unitDisplay be numberFormat.[[UnitDisplay]].
    3. Let patterns be patterns.[[unit]].
    4. If patterns doesn't have a field [[<unit>]], then
      1. Let unit be "fallback".
    5. Let patterns be patterns.[[<unit>]].
    6. Let patterns be patterns.[[<unitDisplay>]].
  9. Else if style is "currency", then
    1. Let currency be numberFormat.[[Currency]].
    2. Let currencyDisplay be numberFormat.[[CurrencyDisplay]].
    3. Let currencySign be numberFormat.[[CurrencySign]].
    4. Let patterns be patterns.[[currency]].
    5. If patterns doesn't have a field [[<currency>]], then
      1. Let currency be "fallback".
    6. Let patterns be patterns.[[<currency>]].
    7. Let patterns be patterns.[[<currencyDisplay>]].
    8. Let patterns be patterns.[[<currencySign>]].
  10. Else,
    1. Assert: style is "decimal".
    2. Let patterns be patterns.[[decimal]].
  11. If x is negative-infinity, then
    1. Let category be negative-nonzero.
  12. Else if x is negative-zero, then
    1. Let category be negative-zero.
  13. Else if x is not-a-number, then
    1. Let category be positive-zero.
  14. Else if x is positive-infinity, then
    1. Let category be positive-nonzero.
  15. Else,
    1. Assert: x is a mathematical value.
    2. If x < 0, then
      1. Let category be negative-nonzero.
    3. Else if x > 0, then
      1. Let category be positive-nonzero.
    4. Else,
      1. Let category be positive-zero.
  16. Let signDisplay be numberFormat.[[SignDisplay]].
  17. If signDisplay is "never", then
    1. Let pattern be patterns.[[zeroPattern]].
  18. Else if signDisplay is "auto", then
    1. If category is positive-nonzero or positive-zero, then
      1. Let pattern be patterns.[[zeroPattern]].
    2. Else,
      1. Let pattern be patterns.[[negativePattern]].
  19. Else if signDisplay is "always", then
    1. If category is positive-nonzero or positive-zero, then
      1. Let pattern be patterns.[[positivePattern]].
    2. Else,
      1. Let pattern be patterns.[[negativePattern]].
  20. Else if signDisplay is "exceptZero", then
    1. If category is positive-zero or negative-zero, then
      1. Let pattern be patterns.[[zeroPattern]].
    2. Else if category is positive-nonzero, then
      1. Let pattern be patterns.[[positivePattern]].
    3. Else,
      1. Let pattern be patterns.[[negativePattern]].
  21. Else,
    1. Assert: signDisplay is "negative".
    2. If category is negative-nonzero, then
      1. Let pattern be patterns.[[negativePattern]].
    3. Else,
      1. Let pattern be patterns.[[zeroPattern]].
  22. Return pattern.

1.5.12 GetNotationSubPattern ( numberFormat, exponent )

The abstract operation GetNotationSubPattern considers the resolved notation and exponent, and returns a String value for the notation sub pattern as described in 1.2.3.

  1. Let localeData be %NumberFormat%.[[LocaleData]].
  2. Let dataLocale be numberFormat.[[DataLocale]].
  3. Let dataLocaleData be localeData.[[<dataLocale>]].
  4. Let notationSubPatterns be dataLocaleData.[[notationSubPatterns]].
  5. Assert: notationSubPatterns is a Record (see 1.2.3).
  6. Let notation be numberFormat.[[Notation]].
  7. If notation is "scientific" or notation is "engineering", then
    1. Return notationSubPatterns.[[scientific]].
  8. Else if exponent is not 0, then
    1. Assert: notation is "compact".
    2. Let compactDisplay be numberFormat.[[CompactDisplay]].
    3. Let compactPatterns be notationSubPatterns.[[compact]].[[<compactDisplay>]].
    4. Return compactPatterns.[[<exponent>]].
  9. Else,
    1. Return "{number}".

1.5.13 ComputeExponent ( numberFormat, x )

The abstract operation ComputeExponent computes an exponent (power of ten) by which to scale x according to the number formatting settings. It handles cases such as 999 rounding up to 1000, requiring a different exponent.

  1. If x = 0, then
    1. Return 0.
  2. If x < 0, then
    1. Let x = -x.
  3. Let magnitude be the base 10 logarithm of x rounded down to the nearest integer.
  4. Let exponent be ComputeExponentForMagnitude(numberFormat, magnitude).
  5. Let x be x × 10-exponent.
  6. Let formatNumberResult be FormatNumericToString(numberFormat, x).
  7. If formatNumberResult.[[RoundedNumber]] = 0, then
    1. Return exponent.
  8. Let newMagnitude be the base 10 logarithm of formatNumberResult.[[RoundedNumber]] rounded down to the nearest integer.
  9. If newMagnitude is magnitude - exponent, then
    1. Return exponent.
  10. Return ComputeExponentForMagnitude(numberFormat, magnitude + 1).

1.5.14 ComputeExponentForMagnitude ( numberFormat, magnitude )

The abstract operation ComputeExponentForMagnitude computes an exponent by which to scale a number of the given magnitude (power of ten of the most significant digit) according to the locale and the desired notation (scientific, engineering, or compact).

  1. Let notation be numberFormat.[[Notation]].
  2. If notation is "standard", then
    1. Return 0.
  3. Else if notation is "scientific", then
    1. Return magnitude.
  4. Else if notation is "engineering", then
    1. Let thousands be the greatest integer that is not greater than magnitude / 3.
    2. Return thousands × 3.
  5. Else,
    1. Assert: notation is "compact".
    2. Let exponent be an implementation- and locale-dependent (ILD) integer by which to scale a number of the given magnitude in compact notation for the current locale.
    3. Return exponent.

1.5.15 Runtime Semantics: StringIntlMV

The syntax-directed operation StringIntlMV takes no arguments.

Note

The conversion of a StringNumericLiteral to a Number value is similar overall to the determination of the NumericValue of a NumericLiteral (see ), but some of the details are different.

It is defined piecewise over the following productions:

StringNumericLiteral ::: StrWhiteSpaceopt
  1. Return 0.
StringNumericLiteral ::: StrWhiteSpaceopt StrNumericLiteral StrWhiteSpaceopt
  1. Return StringIntlMV of StrNumericLiteral.
StrNumericLiteral ::: NonDecimalIntegerLiteral
  1. Return MV of NonDecimalIntegerLiteral.
StrDecimalLiteral ::: - StrUnsignedDecimalLiteral
  1. Let a be StringIntlMV of StrUnsignedDecimalLiteral.
  2. If a is 0, return negative-zero.
  3. If a is positive-infinity, return negative-infinity.
  4. Return -a.
StrUnsignedDecimalLiteral ::: Infinity
  1. Return positive-infinity.
StrUnsignedDecimalLiteral ::: DecimalDigits . DecimalDigitsopt ExponentPartopt
  1. Let a be MV of the first DecimalDigits.
  2. If the second DecimalDigits is present, then
    1. Let b be MV of the second DecimalDigits.
    2. Let n be the number of code points in the second DecimalDigits.
  3. Else,
    1. Let b be 0.
    2. Let n be 0.
  4. If ExponentPart is present, let e be MV of ExponentPart. Otherwise, let e be 0.
  5. Return (a + (b × 10-n)) × 10e.
StrUnsignedDecimalLiteral ::: . DecimalDigits ExponentPartopt
  1. Let b be MV of DecimalDigits.
  2. If ExponentPart is present, let e be MV of ExponentPart. Otherwise, let e be 0.
  3. Let n be the number of code points in DecimalDigits.
  4. Return b × 10e - n.
StrUnsignedDecimalLiteral ::: DecimalDigits ExponentPartopt
  1. Let a be MV of DecimalDigits.
  2. If ExponentPart is present, let e be MV of ExponentPart. Otherwise, let e be 0.
  3. Return a × 10e.

1.5.16 ToIntlMathematicalValue ( value )

The abstract operation ToIntlMathematicalValue takes argument value. It returns value converted to an Intl mathematical value, which is a mathematical value together with positive-infinity, negative-infinity, not-a-number, and negative-zero. This abstract operation is similar to , but a mathematical value can be returned instead of a Number or BigInt, so that exact decimal values can be represented. The following steps are taken:

  1. Let primValue be ? ToPrimitive(value, number).
  2. If Type(primValue) is BigInt, return ℝ(primValue).
  3. If Type(primValue) is String,
    1. Let str be primValue.
  4. Else,
    1. Let x be ? ToNumber(primValue).
    2. If x is -0𝔽, return negative-zero.
    3. Let str be ! Number::toString(x).
  5. Let text be ! StringToCodePoints(str).
  6. Let literal be ParseText(text, StringNumericLiteral).
  7. If literal is a List of errors, return not-a-number.
  8. Let intlMV be the StringIntlMV of literal.
  9. If intlMV is a mathematical value, then
    1. Let rounded be RoundMVResult(abs(intlMV)).
    2. If rounded is +∞𝔽 and intlMV < 0, return negative-infinity.
    3. If rounded is +∞𝔽, return positive-infinity.
    4. If rounded is +0𝔽 and intlMV < 0, return negative-zero.
    5. If rounded is +0𝔽, return 0.
  10. Return intlMV.

1.5.17 GetUnsignedRoundingMode ( roundingMode, isNegative )

The abstract operation GetUnsignedRoundingMode returns the rounding mode that should be applied to the absolute value of a number to produce the same result as if roundingMode, one of the String values in the Identifier column of Table 2, were applied to the signed value of the number (negative if the boolean isNegative is true, or positive otherwise). The following steps are taken:

  1. If isNegative is true, return the specification type in the third column of Table 4 where the first column is roundingMode and the second column is "negative".
  2. Else, return the specification type in the third column of Table 4 where the first column is roundingMode and the second column is "positive".
Table 4: Conversion from rounding mode to unsigned rounding mode
Identifier Sign Unsigned Rounding Mode
"ceil" positive infinity
negative zero
"floor" positive zero
negative infinity
"expand" positive infinity
negative infinity
"trunc" positive zero
negative zero
"halfCeil" positive half-infinity
negative half-zero
"halfFloor" positive half-zero
negative half-infinity
"halfExpand" positive half-infinity
negative half-infinity
"halfTrunc" positive half-zero
negative half-zero
"halfEven" positive half-even
negative half-even

1.5.18 ApplyUnsignedRoundingMode ( x, r1, r2, unsignedRoundingMode )

The abstract operation ApplyUnsignedRoundingMode considers x (a mathematical value), bracketed below by r1 (a mathematical value) and above by r2 (a mathematical value), and returns either r1 or r2 according to unsignedRoundingMode (a specification type from the Unsigned Rounding Mode column of Table 4 or undefined). The following steps are taken:

  1. If x is equal to r1, return r1.
  2. Assert: r1 < x < r2.
  3. Assert: unsignedRoundingMode is not undefined.
  4. If unsignedRoundingMode is zero, return r1.
  5. If unsignedRoundingMode is infinity, return r2.
  6. Let d1 be xr1.
  7. Let d2 be r2x.
  8. If d1 < d2, return r1.
  9. If d2 < d1, return r2.
  10. Assert: d1 is equal to d2.
  11. If unsignedRoundingMode is half-zero, return r1.
  12. If unsignedRoundingMode is half-infinity, return r2.
  13. Assert: unsignedRoundingMode is half-even.
  14. Let cardinality be (r1 / (r2r1)) modulo 2.
  15. If cardinality is 0, return r1.
  16. Return r2.

1.5.19 PartitionNumberRangePattern ( numberFormat, x, y )

The abstract operation PartitionNumberRangePattern creates the parts for a localized number range according to x (which must be an Intl mathematical value), y (which must be an Intl mathematical value), and the formatting options of numberFormat (which must be an object initialized as NumberFormat). The following steps are taken:

  1. If x is not-a-number or y is not-a-number, throw a RangeError exception.
  2. Let result be a new empty List.
  3. Let xResult be ? PartitionNumberPattern(numberFormat, x).
  4. Let yResult be ? PartitionNumberPattern(numberFormat, y).
  5. If xResult is equal to yResult, then
    1. Let appxResult be ? FormatApproximately(numberFormat, xResult).
    2. For each r in appxResult, do
      1. Set r.[[Source]] to "shared".
    3. Return appxResult.
  6. For each r in xResult, do
    1. Set r.[[Source]] to "startRange".
  7. Add all elements in xResult to result in order.
  8. Let rangeSeparator be an ILND String value used to separate two numbers.
  9. Append a new Record { [[Type]]: "literal", [[Value]]: rangeSeparator, [[Source]]: "shared" } element to result.
  10. For each r in yResult, do
    1. Set r.[[Source]] to "endRange".
  11. Add all elements in yResult to result in order.
  12. Return ! CollapseNumberRange(result).

1.5.20 FormatApproximately ( numberFormat, result )

The FormatApproximately abstract operation modifies result, which must be a List of Record values as described in PartitionNumberPattern, by adding a new Record for the approximately sign, which may depend on numberFormat (which must be an object initialized as NumberFormat). The following steps are taken:

  1. Let i be an index into result, determined by an implementation-defined algorithm based on numberFormat and result.
  2. Let approximatelySign be an ILND String value used to signify that a number is approximate.
  3. If approximatelySign is not empty, insert a new Record { [[Type]]: "approximatelySign", [[Value]]: approximatelySign } at index i in result.
  4. Return result.

1.5.21 CollapseNumberRange ( result )

The CollapseNumberRange abstract operation modifies result, which must be a List of Record values as described in PartitionNumberRangePattern, by removing redundant information, and returns the resulting List. The algorithm is implementation dependent, but it must not introduce ambiguity: the resulting list after modification should be unique for all pairs x and y.

For example, an implementation may choose to remove the currency symbol following the range separator, to produce "$3–5" instead of "$3–$5".

The implementation may choose to modify symbols for grammatical correctness; for example, "0.5 miles–1 mile" may become "0.5–1 miles".

Returning result unmodified is guaranteed to be a correct implementation of CollapseNumberRange.

1.5.22 FormatNumericRange( numberFormat, x, y )

The FormatNumericRange abstract operation is called with arguments numberFormat (which must be an object initialized as a NumberFormat), x (which must be an Intl mathematical value), and y (which must be an Intl mathematical value greater than or equal to x), and performs the following steps:

  1. Let parts be ? PartitionNumberRangePattern(numberFormat, x, y).
  2. Let result be the empty String.
  3. For each part in parts, do
    1. Set result to the string-concatenation of result and part.[[Value]].
  4. Return result.

1.5.23 FormatNumericRangeToParts( numberFormat, x, y )

The FormatNumericRangeToParts abstract operation is called with arguments numberFormat (which must be an object initialized as a NumberFormat), x (which must be an Intl mathematical value), and y (which must be an Intl mathematical value greater than or equal to x), and performs the following steps:

  1. Let parts be ? PartitionNumberRangePattern(numberFormat, x, y).
  2. Let result be ArrayCreate(0).
  3. Let n be 0.
  4. For each part in parts, do
    1. Let O be ObjectCreate(%ObjectPrototype%).
    2. Perform ! CreateDataPropertyOrThrow(O, "type", part.[[Type]]).
    3. Perform ! CreateDataPropertyOrThrow(O, "value", part.[[Value]]).
    4. Perform ! CreateDataPropertyOrThrow(O, "source", part.[[Source]]).
    5. Perform ! CreateDataPropertyOrThrow(result, ! ToString(n), O).
    6. Increment n by 1.
  5. Return result.