Округление валютных значений в международной локализации в JavaScript
определяется не только математическими правилами, но и набором
стандартов, учитывающих валюту, региональные соглашения и специфику
отображения денежных единиц. Основным инструментом выступает
Intl.NumberFormat, поведение которого при работе с валютами
значительно отличается от обычного форматирования чисел.
При использовании режима форматирования
style: "currency" округление определяется сразу несколькими
уровнями:
Intl.NumberFormat,Каждая валюта имеет фиксированное количество знаков после запятой, называемое minor unit.
Например:
Это поведение применяется автоматически:
new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD"
}).format(10.235);
Результат:
$10.23
Округление произошло по стандартному правилу валюты USD.
Ключевую роль играют параметры:
minimumFractionDigitsmaximumFractionDigitsПри валютном стиле они по умолчанию устанавливаются на основе валюты.
new Intl.NumberFormat("en-US", {
style: "currency",
currency: "JPY"
}).format(1234.56);
Результат:
¥1,235
Несмотря на отсутствие дробной части у JPY, значение было округлено до ближайшего целого числа.
Если переопределить поведение:
new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
maximumFractionDigits: 0
}).format(10.75);
Результат:
$11
Система принудительно игнорирует стандарт валюты и применяет пользовательское правило.
Современная спецификация ECMA-402 (Intl API) вводит параметр
roundingMode, который управляет стратегией округления.
Поддерживаемые режимы:
ceil — всегда вверхfloor — всегда внизexpand — в сторону увеличения по абсолютному
значениюtrunc — усечениеhalfCeil — половина вверхhalfFloor — половина внизhalfExpand — классическое банковское округление вверх
при 0.5halfTrunc — половина к нулюhalfEven — банковское округление к ближайшему
чётномуПример:
new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
roundingMode: "halfEven",
maximumFractionDigits: 2
}).format(1.235);
Результат зависит от стратегии округления и может отличаться от
привычного toFixed.
Каждая валюта в стандарте ISO 4217 содержит поле minor unit digits, которое автоматически определяет:
Примеры:
| Валюта | Minor units | Пример результата |
|---|---|---|
| USD | 2 | 10.23 |
| JPY | 0 | 10 |
| BHD | 3 | 10.235 |
При этом библиотека не хранит эти данные внутри JavaScript — они подгружаются из ICU (International Components for Unicode), используемого движком.
Разработчик может принудительно изменить стандартное округление:
new Intl.NumberFormat("en-US", {
style: "currency",
currency: "JPY",
minimumFractionDigits: 2,
maximumFractionDigits: 2
}).format(1234.5);
Результат:
¥1,234.50
В этом случае форматирование перестаёт соответствовать реальным стандартам валюты и становится чисто визуальным.
Банковские и финансовые системы часто используют
halfEven, чтобы минимизировать накопление ошибок при
больших массивах операций.
new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
roundingMode: "halfEven",
maximumFractionDigits: 2
}).format(2.675);
Поведение может отличаться от Math.round, поскольку
используется контекстная арифметика округления, а не стандартное
преобразование числа.
При форматировании валюты происходит последовательная цепочка преобразований:
minimumFractionDigits /
maximumFractionDigits.roundingMode.Важно, что округление происходит до этапа локализации строки, а не после.
toLocaleString и Intl.NumberFormattoLocaleString является обёрткой над
Intl.NumberFormat, но поведение при округлении
идентично:
(10.235).toLocaleString("en-US", {
style: "currency",
currency: "USD"
});
Тем не менее Intl.NumberFormat предпочтительнее при
массовом форматировании из-за возможности переиспользования
экземпляра.
JavaScript использует IEEE 754, поэтому значения вроде:
0.1 + 0.2
могут давать неточное представление до округления. Intl API компенсирует это на этапе форматирования:
new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
maximumFractionDigits: 2
}).format(0.1 + 0.2);
Результат:
$0.30
Округление и отображение символа валюты связаны, но независимы. Например:
"en-US" vs
"ru-RU").new Intl.NumberFormat("ru-RU", {
style: "currency",
currency: "USD"
}).format(1234.5);
Результат:
1 234,50 $
Для валют без дробной части система полностью подавляет десятичную запись:
new Intl.NumberFormat("en-US", {
style: "currency",
currency: "JPY"
}).format(99.99);
Результат:
¥100
Даже если передано дробное значение, оно приводится к целому по правилам округления валюты.
Intl.NumberFormat поддерживает BigInt, но
правила округления применяются только к дробным типам. Для целых
значений округление не выполняется:
new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD"
}).format(12345678901234567890n);
Результат:
$12,345,678,901,234,567,890.00
Дробная часть добавляется автоматически из-за валютного формата USD.
Система округления валют в Intl API представляет собой многоуровневую модель, где итоговое значение формируется не одной функцией, а комбинацией стандартов ICU, правил ISO 4217 и пользовательских параметров форматирования.