Калькулятор округления до цента
Результат
Округлённое значение
- Центы
- 268
Округлить сумму до ближайшего цента — значит обрезать её до двух знаков после запятой, причём суммы ровно в половину цента уходят от нуля: 2,675 становится 2,68, а 0,005 становится 0,01. Это последний шаг почти любого денежного расчёта, потому что цена, умноженная на количество, или ставка, применённая к промежуточной сумме, почти никогда не попадает ровно на целое число центов. Сделать это правильно труднее, чем кажется. Прямой путь — умножить на 100, округлить до целого и разделить обратно — и отказывает он ровно на тех суммах, которые людям и важны: 1,005, умноженное на 100, даёт 100,49999999999999, а не 100,5, поэтому число округляется вниз до 1,00 и последний цент беззвучно исчезает. Печать значения с двумя знаками после запятой имеет ту же проблему по той же причине: она смотрит на то же чуть-чуть слишком маленькое число. Ни один из этих отказов себя не объявляет. На выходе вполне обычная на вид сумма, и заметить подвох можно, только зная, каким должен был быть ответ. Эта страница обходит ловушку, перенося запятую как текст, а не умножением, поэтому решение принимается по точному значению. Она же сообщает сумму целым числом центов — это та форма, которую стоит сохранять, если вы собираетесь делать с ней ещё что-то. Результат записывается так, как ваш язык записывает деньги: русский читатель видит сумму в тысячу двести тридцать четыре и пятьдесят семь сотых как 1 234,57, тогда как английский видит те же деньги как 1,234.57, а немецкий — как 1.234,57. Две суммы, различающиеся только последним центом, возвращаются разными числами — в этом всё и дело.
Четыре суммы, которые выглядят обычными и округляются не туда
| Сумма | Округлённое | Центы |
|---|---|---|
| 2.675 | 2.68 | 268 |
| 1.005 | 1.01 | 101 |
| 0.005 | 0.01 | 1 |
| -0.005 | -0.01 | -1 |
Каждая строка здесь — сумма, на которой прямолинейная реализация ошибается, и ошибается по своей собственной причине. 2,675 — пример, которым пользуются все, и единственный случай, где умножение на сто случайно работает: оно попадает точно на 267,5. Так что это плохой образец и хорошее предупреждение: читатель, проверивший только эту строку, обнаружит, что его собственный код согласен со страницей, и заключит, что чинить нечего. 1,005 — настоящий отказ: у сотой доли нет точной двоичной записи, поэтому умножение даёт 100,49999999999999, и оба очевидных метода отвечают 1,00. 0,005 — ровно половина цента, она уходит от нуля, а на положительной сумме это то же самое, что уйти вверх. А -0,005 — та же сумма со знаком, и здесь два правила расходятся: округление отрицательной половины к плюс бесконечности даёт отрицательный ноль, который печатается как -0,00. Третий столбец идёт рядом, чтобы каждая строка показывала два взгляда на одну сумму — десятичную дробь слева от него и целое число центов справа, причём считается оно от уже округлённой суммы, так что разойтись эти двое не могут. Числа в таблице приведены как есть, без локализации: разделитель дробной части в ней — точка (2.675, а не 2,675), и разряды в ней не группируются (123457, а не 123 457), тогда как панель результата выше и то и другое делает по правилам вашего языка.
Формула
2,675 → 2,68; 1,005 → 1,01; 0,005 → 0,01; -0,005 → -0,01; центы = округлённое * 100
- значение
- Сумма, которую нужно округлить, — от минус миллиарда до плюс миллиарда. Больше двух знаков после запятой принимается намеренно: 1,005 и 2,675 — это ровно то, ради чего страница и сделана, и ввод, который бы их отвергал, отворачивался бы от тех самых случаев, для которых он существует. Поле не требует двух знаков после запятой и не должно требовать: предмет здесь — правило округления, а не формат ввода
- округлённое
- Сумма после округления до двух знаков после запятой, первая строка результата. Это число, а не текст, и именно поэтому оно записывается с десятичным знаком и разделителями разрядов вашего языка: 1 234,57 по-русски, 1,234.57 по-английски, 1.234,57 по-немецки. Это отличие от страницы округления намеренное и на одном и том же вводе оно единственное
- центы
- Та же сумма, выраженная целым числом центов: это отдельный вывод, а не второй способ записать первый. 268 — целое число, с которым можно складывать, делить и считать; 2,68 — десятичная дробь, которая снова превращается в число с плавающей запятой, как только вы её на что-нибудь умножите. Считается она от уже округлённой суммы, а не от исходной, поэтому две строки не могут разойтись: 1,005 даёт 1,01 рядом с 101, но никогда 1,01 рядом с 100
- половина от нуля
- Правило для сумм, стоящих ровно на половине цента: 0,005 уходит в 0,01, а -0,005 — в -0,01. Округление вверх и округление от нуля совпадают на положительных суммах и расходятся на отрицательных, и именно там это различие себя оправдывает: наивный целочисленный метод возвращает здесь отрицательный ноль, а -0,00 — не то, что стоит показывать кому-либо как сумму долга
- 1,005 * 100 = 100,49999999999999
- Тот самый отказ, вокруг которого построена страница. Сотая доля не представима в двоичном виде точно, поэтому умножение на сто попадает чуть ниже точки деления пополам, и округление уходит не в ту сторону. Любой метод, который сначала умножает, — а дальше он округляет число или форматирует его до двух знаков — наследует эту ошибку и отвечает 1,00. Перенос запятой в тексте сохраняет значение точным, и ответ выходит 1,01
- -0,005 → -0,01
- Отрицательная половина цента и случай, где два правила округления расходятся. Сумма стоит ровно на половину цента ниже нуля, и правило отправляет её дальше от нуля, а не вверх, поэтому получается -0,01, а не -0,00. Округление отрицательной половины к плюс бесконечности даёт отрицательный ноль: он печатается как -0,00 и читается как ошибка округления, хотя арифметика была непротиворечивой
Любой расчёт, который заканчивается деньгами, заканчивается здесь. Счёт, разделённый между несколькими людьми, почти никогда не делится на целые центы, и остаток приходится кому-то приписывать или куда-то округлять; налог или чаевые, применённые к промежуточной сумме, дают сумму с большим числом знаков, чем бывает у денег; цена за единицу, умноженная на количество, делает то же самое. Округлить в конце — очевидный шаг, но важнее округлять в середине. График погашения считает проценты на остаток за каждый период и округляет проценты каждого периода до цента, прежде чем прибавить их обратно, потому что округление только в конце позволяет дробным частям накапливаться: на трёхстах шестидесяти периодах этот дрейф — целые доллары, и итоговый остаток перестаёт совпадать с тем, что у кредитора. То же соображение работает всюду, где итог собирается из округлённых частей: сначала округляются части и лишь потом складываются, а не наоборот. Целое число центов — та форма, которую для такой работы и стоит держать: это целое, и оно остаётся точным до самого конца. Там же, где вопрос про десятичные разряды вообще, а не про деньги, — измерение до трёх знаков, цифра до двух значащих — страница округления покрывает тринадцать разных целей в одном месте; эта страница покрывает одну цель, которой пользуются деньги, и делает это правилом, в котором арифметика ошибиться не может.
Разобранные примеры
Сумма по умолчанию: 2,675
- Сумма лежит между 2,67 и 2,68 и стоит ровно посередине между ними
- Половина уходит от нуля, поэтому ответ 2,68, а не 2,67
- Умножаем округлённую сумму на 100: 2,68 × 100 = 268
- Ответ — это сумма в два доллара шестьдесят восемь центов, то есть 268 центов
Пример, к которому тянутся все, и потому он здесь по умолчанию. Это ещё и единственный случай, где наивный метод случайно даёт верный ответ: 2,675, умноженное на 100, попадает в двоичном виде ровно на 267,5, а 1,005 — нет. Так что будь это единственным образцом на странице, читатель, сверяющий его со своим кодом, обнаружил бы совпадение и заключил, что решать нечего. Разницу показывает следующий пример — поэтому на экране страница открывается этой суммой, а другую разбирает ниже.
Сумма, на которой спотыкаются все: 1,005
- Сумма стоит ровно посередине между 1,00 и 1,01
- Половина уходит от нуля, поэтому ответ 1,01
- Умножение на сто даёт 100,49999999999999, а не 100,5: у сотой доли нет точной двоичной записи
- Поэтому метод, который сначала умножает, округляет вниз и отвечает 1,00, теряя цент
- Перенос запятой в тексте сохраняет значение точным, и на выходе получается 1,01
Пример, ради которого эта страница и существует. Умножьте на сто — получите 100,49999999999999, и не случайно чуть ниже точки деления пополам, а потому что 1,005 не представимо в двоичном виде точно и сохранённое значение чуть меньше настоящего. Оба очевидных метода наследуют эту ошибку: округление умноженного числа даёт 1,00, и форматирование значения до двух знаков тоже даёт 1,00, потому что оба смотрят на одно и то же чуть-чуть слишком маленькое число. В выводе ничто не выглядит неправильным. Цент просто исчез, и поймать это можно, только зная, каким ответ должен был быть. Суммы в половину цента — это ровно то, на что денежные расчёты и попадают, ведь ставка, применённая к некруглой цене, производит их постоянно.
Обычная сумма с лишними знаками: 1 234,5678
- Первые два знака после запятой — 56, а следом идёт 78, то есть больше половины цента
- Значит второй знак после запятой поднимается: 1 234,57
- Умножаем на 100: 1 234,57 × 100 = 123 457
- Словами сумма читается как тысяча двести тридцать четыре и пятьдесят семь центов
Ничем не примечательный случай, и он стоит одного примера, чтобы страница не состояла из одних ловушек. Ничего хитрого не происходит: третий знак после запятой — 7, поэтому сумма округляется вверх обычным образом, и оба метода согласны друг с другом. Зато этот случай показывает запись, а это первое, что замечает читатель. По-русски сумма возвращается как 1 234,57: разряды разделены неразрывным пробелом, а перед центами стоит запятая. По-английски она вернётся как 1,234.57, где эти два знака поменяны местами, по-немецки — как 1.234,57, а по-французски — с узким пробелом там, где у нас неразрывный. Цифры одинаковы, и страница их не трогает: меняется то, как ваш язык записывает деньги, и эта страница за языком следует, тогда как страница округления намеренно нет.
Половина цента ниже нуля: -0,005
- Сумма стоит ровно посередине между нулём и минус одним центом
- Половина уходит от нуля, а здесь это значит вниз: -0,01
- Умножение на 100 даёт ровно -0,5, так что этот случай масштабируется чисто
- Округление -0,5 до целого наивным способом даёт отрицательный ноль, который печатается как -0,00
- Перенос запятой в тексте даёт -1 цент, а суммой -0,01
Случай, который разделяет два правила округления. На положительных суммах округление половины вверх и округление половины от нуля совпадают, так что различие выглядит придиркой. Здесь они расходятся: округление -0,5 вверх даёт ноль со знаком минус, а сумма в минус ноль центов — не то, что кому-либо стоит показывать. Этот случай к тому же масштабируется чисто: -0,005, умноженное на 100, равно ровно -0,5 — двоичный сбой не симметричен относительно знака, поэтому набор проверочных сумм нуждается в отрицательных не меньше, чем в положительных. Возврат, зачёт или скидка, превышающая сумму, попадают именно сюда.
Ограничения
Сумма должна быть числом от минус миллиарда до плюс миллиарда, и округлённый результат может оказаться на шаг за этой границей: 999 999 999,999 округляется ровно до миллиарда, а вывод в центах там — сто миллиардов. Выводы остаются точными при таком размере, потому что целое число центов такой величины всё ещё лежит внутри диапазона, где целые представляются точно. Правило округления — половина от нуля, и настройки, чтобы его сменить, нет: страница с переключателем правила должна была бы объяснять, какое правило применяют суды в вашей стране, а она этого не делает. Отрицательные суммы округляются от нуля, а не вверх, и расходятся эти два правила ровно на случаях в половину цента. Валюта странице неизвестна: она знает, сколько центов составляет сумма, но не знает, как эти центы называются, поэтому вывод — число, а любой символ добавляйте сами. Она округляет по одной сумме за раз и не делит итог между людьми, не распределяет остатки и не сводит график платежей. Таблица ниже показывает четыре фиксированные суммы, а не следует за вашим вводом, и числа в ней напечатаны без локализации, поэтому они читаются как 2.675 и -0.005 на любом языке, хотя панель результата выше локализацию выполняет.
Частые вопросы
- Почему 1,005 округляется до 1,01, а не до 1,00?
- Потому что это ровно половина между 1,00 и 1,01, а правило для половин отправляет сумму от нуля. Ответ кажется неожиданным только потому, что очевидные реализации возвращают 1,00. Умножьте 1,005 на сто — получите 100,49999999999999, а не 100,5: сотая доля не представима в двоичном виде точно, и сохранённое значение чуть меньше настоящего. Поэтому метод, который сначала масштабирует, — а дальше он округляет число или форматирует его до двух знаков — смотрит на значение чуть ниже точки деления пополам и округляет вниз. Цент при этом не пропадает со скандалом: на выходе самая обычная на вид сумма. Именно из-за этого одного ввода здесь целая страница, а не формула в одну строку.
- Округляется половина вверх или к чётному?
- Половина от нуля: вверх на положительных суммах и вниз на отрицательных. Так поступает почти любая кассовая система, и это же человек имеет в виду, когда просит округлить цену, поэтому 2,5 цента становятся 3, а -2,5 цента становятся -3. Округление половины к чётному — другое распространённое правило, и оно существует, чтобы длинные столбцы чисел не уползали вверх при сложении; оно важно в статистике и в части бухгалтерской работы, и эта страница делает не его. Два правила совпадают на всех суммах, кроме ровных половин, поэтому разницу легко не заметить, пока выплата не попадёт ровно на такую. Переключателя нет, потому что переключателю пришлось бы объяснять, какое правило применяется в какой юрисдикции.
- Зачем показывать число центов вдобавок к сумме?
- Потому что эти двое полезны для разного, и именно целое число остаётся точным. Двести шестьдесят восемь — целое: его можно складывать с другими целыми центами, делить между людьми, умножать на количество и продолжать, и с ним ничего не случится. Два и шестьдесят восемь сотых — десятичная дробь, и как только вы её на что-нибудь умножите, она снова станет числом с плавающей запятой с той же проблемой представления, от которой вы сюда и пришли. Поэтому же центы считаются от уже округлённой суммы, а не от исходного ввода: считайся они отдельно, ввод вроде 1,005 мог бы напечатать 1,01 в одной строке и 100 в следующей, а два числа на одной панели, которые друг другу противоречат, хуже, чем любое из них по отдельности.
- Почему ответ на этой странице записан не так, как на странице округления?
- Потому что вывод этой страницы — число, а вывод той — текст с фиксированной точкой и без разделителей разрядов. Здесь сумму пишет ваш язык: по-русски 1 234,57, где разряды разделены неразрывным пробелом, а перед центами стоит запятая. Английский записал бы те же деньги как 1,234.57, поменяв эти два знака местами, немецкий — как 1.234,57, а французский — как 1 234,57, то есть так же, как русский, но с более узким пробелом. Страница округления устроена иначе намеренно: её результат — текст, точка там всегда точка, а разряды не группируются вовсе, поэтому на том же вводе 1 234,5678 и том же разряде — «Сотых (0,01)» — она напечатает 1234.57. Это единственное место, где две страницы действительно расходятся на одинаковых данных, и расхождение это осознанное.
- Где округление до цента вообще важно?
- Там, где итог собирается из частей. График погашения — самый ясный случай: проценты каждого периода считаются на остаток, округляются до цента и прибавляются обратно, а округление один раз в конце позволяет остаткам дробей накапливаться: на трёхстах шестидесяти периодах этот дрейф — целые доллары, и итоговый остаток перестаёт сходиться с тем, что у кредитора. Раздел счёта устроен так же, ведь итог, поделённый между несколькими людьми, редко попадает на целые центы, и лишний цент приходится куда-то девать. А любая ставка, применённая к сумме, — налог, чаевые, скидка — даёт больше знаков, чем бывает у денег. Правило, которое стоит отсюда унести: сначала округляются части, а потом складываются уже округлённые, а не наоборот.
- Какую наибольшую сумму страница принимает?
- Денежная сумма принимается в пределах от минус миллиарда до плюс миллиарда, а округлённый ответ может оказаться на шаг за этой границей: 999 999 999,999 округляется ровно до миллиарда, и вывод в центах там — сто миллиардов. Выводы остаются точными при таком размере, потому что целое число центов такой величины всё ещё лежит внутри диапазона, где каждое целое представляется точно; потолок стоит куда ниже той точки, где целые начинают приближаться. Ввод за границей отклоняется, а не подрезается: тихо округлить сумму, которую вы не вводили, было бы худшим ответом, чем сказать «нет».
Источники
- Rounding — the half-away-from-zero rule, and how it differs from rounding half upward on negative values — Wolfram MathWorld (United States)
- What Every Computer Scientist Should Know About Floating-Point Arithmetic — why 1.005 stored as a double is a hair below the half-way point — Oracle (originally ACM Computing Surveys)
- Number.prototype.toFixed — the round-half-to-even behaviour, and why formatting a value to two decimals is not the same as rounding it — MDN Web Docs (Mozilla)