Round, roundf, roundlround, roundf, roundl

Работающие реализации на Go

Round(), используемая в Postgres

Выше я уже упоминал, что в Postgres содержится код функции Round() на C, который работает для всех тестируемых значений. В CockroachDB мы , без комментариев он выглядит следующим образом:

Давайте разберёмся, как он работает. Первые шесть строк обрабатывают особые случаи. Далее мы выбираем roundFn из Ceil и Floor в зависимости от того, положительное число или отрицательное. Далее начинается самое интересное:

Этим кодом мы сдвигаем x ближе к нулю.

Далее мы проверяем, не стал ли x в точности нулём и не поменялся ли у него знак. Это означает что исходное число <= 0,5, в этом случае мы возвращаем ноль с нужным знаком.

Эта проверка нужна для очень больших чисел, для которых x-0,5 == x-1,0, в этих случаях мы можем вернуть число неизменённым.

Далее мы округляем число с помощью Floor() или Ceil() и возвращаем это значение, если оно отличается от x, что может случиться, только если дробная часть входного значения не равна в точности 0,5, так как выше мы вычли 0,5 из него.

Теперь мы знаем, что дробная часть равна 0,5, поэтому нам нужно округлить до ближайшего чётного числа (реализация Round() в Postgres в этом месте отличается от приведённых выше вариантов). Комментарий в коде лучше это описывает:

Чтобы сохранить оригинальное поведение, этот код можно заменить на следующий:

github.com/montanaflynn/stats

Ещё одна работающая реализация содержится в пакете github.com/montanaflynn/stats. Без комментариев она выглядит следующим образом:

Ключевое отличие от предыдущих решений заключается в использовании функции Modf(), которая корректно разделяет целую и дробную части чисел.

Методы

В разных сферах могут применяться различные методы округления. Во всех этих методах «лишние» знаки обнуляют (отбрасывают), а предшествующий им знак корректируется по какому-либо правилу.

  • Округление к ближайшему целому (англ. rounding) — наиболее часто используемое округление, при котором число округляется до целого, модуль разности с которым у этого числа минимален. В общем случае, когда число в десятичной системе округляют до N-го знака, правило может быть сформулировано следующим образом:

    • если N+1 знак < 5, то N-й знак сохраняют, а N+1 и все последующие обнуляют;
    • если N+1 знак ≥ 5, то N-й знак увеличивают на единицу, а N+1 и все последующие обнуляют;
    Например: 11,9 → 12; −0,9 → −1; −1,1 → −1; 2,5 → 3.
    Максимальная дополнительная абсолютная погрешность, вносимая при таком округлении (погрешность округления), составляет ±0,5 последнего сохраняемого разряда.
  • Округление к меньшему по модулю (округление к нулю, целое англ. fix, truncate, integer) — самое «простое» округление, поскольку после обнуления «лишних» знаков предшествующий знак сохраняют, то есть технически оно состоит в отбрасывании лишних знаков. Например, 11,9 → 11; −0,9 → 0; −1,1 → −1). При таком округлении может вноситься погрешность в пределах единицы последнего сохраняемого разряда, причём в положительной части числовой оси погрешность всегда отрицательна, а в отрицательной — положительна.
  • Округление к большему (округление к +∞, округление вверх, англ. ceiling — досл. «потолок») — если обнуляемые знаки не равны нулю, предшествующий знак увеличивают на единицу, если число положительное, или сохраняют, если число отрицательное. В экономическом жаргоне — округление в пользу продавца, кредитора (лица, получающего деньги). В частности, 2,6 → 3, −2,6 → −2. Погрешность округления — в пределах +1 последнего сохраняемого разряда.
  • Округление к меньшему (округление к −∞, округление вниз, англ. floor — досл. «пол») — если обнуляемые знаки не равны нулю, предшествующий знак сохраняют, если число положительное, или увеличивают на единицу, если число отрицательное. В экономическом жаргоне — округление в пользу покупателя, дебитора (лица, отдающего деньги). Здесь 2,6 → 2, −2,6 → −3. Погрешность округления — в пределах −1 последнего сохраняемого разряда.
  • Округление к большему по модулю (округление к бесконечности, округление от нуля) — относительно редко используемая форма округления. Если обнуляемые знаки не равны нулю, предшествующий знак увеличивают на единицу. Погрешность округления составляет +1 последнего разряда для положительных и −1 последнего разряда для отрицательных чисел.

Различие округления в Python 2 и Python 3

В Python 2 и Python 3 реализованы разные принципы округления.

В Python 2 используется арифметическое округление. В нем наблюдается большое количество погрешностей, что приводит к неточностям в процессе вычислений.

Во втором Python есть только 4 цифры, которые ведут к преобразованию к меньшему значению – 1, 2, 3 и 4. Также 5 цифр, которые приводят к большему значению – 5, 6, 7, 8, 9. Такое неравное распределение ведет к тому, что погрешность постоянно нарастает.

Python 2 по правилам арифметического округления преобразует число 5,685 в 5,68 до второго знака. Такая погрешность связана с тем, что десятичные цифры float в двоичном коде невозможно корректно представить.

В Python 3 используются принципы банковского округления. Это означает, что преобразование производится к ближайшему четному. В таком случае также не удается полностью избежать возникающих ошибок, но программисты добиваются точности в подсчетах.

2,5 по правилам банковского преобразования будет равно 2, а 3,5 = 4 (значения возводятся к близкому четному). Минимизировать погрешности можно благодаря практически равной вероятности, что перед пятеркой будет четное или нечетное число.

Второе правило округления

Второе правило округления выглядит следующим образом:

Если при округлении чисел первая из отбрасываемых цифр 5, 6, 7, 8 или 9, то сохраняемая цифра увеличивается на единицу.

Например, округлим число 675 до разряда десятков.

В первую очередь находим сохраняемую цифру. Для этого надо прочитать само задание. В разряде, о котором говорится в задании и находится сохраняемая цифра. В задании сказано: округлить число 675 до разряда десятков.

Видим, что в разряде десятков находится семёрка. Значит сохраняемой цифрой является цифра 7

Теперь находим первую из отбрасываемых цифр. Первой из отбрасываемых цифр является та цифра, которая следует после сохраняемой цифрой. Видим, что первая цифра после семёрки это цифра 5. Значит цифра 5 является первой отбрасываемой цифрой.

Теперь применяем второе правило округления. Оно говорит, что если при округлении чисел первая из отбрасываемых цифр 5, 6, 7, 8 или 9, то сохраняемая цифра увеличивается на единицу.

У нас первая из отбрасываемых цифр это 5. Значит мы должны увеличить на единицу сохраняемую цифру 7, а всё что следует после неё заменить нулём:

675 ≈ 680

Значит при округлении числа 675 до разряда десятков, получаем приближённое ему число 680.

Теперь попробуем округлить то же самое число 675, но уже до разряда сотен.

Нам требуется округлить число 675 до разряда сотен. Снова ищем сохраняемую цифру. В этот раз сохраняемой цифрой является 6, поскольку мы округляем число до разряда сотен:

Теперь находим первую из отбрасываемых цифр. Первой из отбрасываемых цифр является та цифра, которая следует после сохраняемой цифрой. Видим, что первая цифра после шестёрки это цифра 7. Значит цифра 7 является первой отбрасываемой цифрой:

Теперь применяем второе правило округления. Оно говорит, что если при округлении чисел первая из отбрасываемых цифр 5, 6, 7, 8 или 9, то сохраняемая цифра увеличивается на единицу.

У нас первая из отбрасываемых цифр это 7. Значит мы должны увеличить на единицу сохраняемую цифру 6, а всё что следует после неё заменить нулями:

675 ≈ 700

Значит при округлении числа 675 до разряда сотен, получаем приближённое ему число 700.

Пример 3. Округлить число 9876 до разряда десятков.

Здесь сохраняемая цифра это 7. А первая отбрасываемая цифра это 6. Согласно правилу, если при округлении чисел первая из отбрасываемых цифр 5, 6, 7, 8 или 9, то сохраняемая цифра увеличивается на единицу.

Значит увеличиваем на единицу сохраняемую цифру 7, а всё что располагается после неё заменяем нулём:

9876 ≈ 9880

Пример 4. Округлить число 9876 до разряда сотен.

Здесь сохраняемая цифра это 8. А первая отбрасываемая цифра это 7. Согласно правилу, если при округлении чисел первая из отбрасываемых цифр 5, 6, 7, 8 или 9, то сохраняемая цифра увеличивается на единицу.

Значит увеличиваем на единицу сохраняемую цифру 8, а всё что располагается после неё заменяем нулями:

9876 ≈ 9900

Пример 5. Округлить число 9876 до разряда тысяч.

Здесь сохраняемая цифра это 9. А первая отбрасываемая цифра это 8. Согласно правилу, если при округлении чисел первая из отбрасываемых цифр 5, 6, 7, 8 или 9, то сохраняемая цифра увеличивается на единицу.

Значит увеличиваем на единицу сохраняемую цифру 9, а всё что располагается после неё заменяем нулями:

9876 ≈ 10000

Пример 6. Округлить число 2971 до сотен.

При округлении этого числа до сотен следует быть внимательным, поскольку сохраняемая цифра здесь 9, а первая отбрасываемая цифра это 7. Значит цифра 9 должна увеличиться на единицу. Но дело в том, что после увеличения девятки на единицу получится 10, а это цифра не вместится в разряд сотен нового числа.

В этом случае, в разряде сотен нового числа надо записать 0, а единицу перенести на следующий разряд и сложить с цифрой, которая там находится. Далее заменить все цифры после сохраняемой нулями:

2971 ≈ 3000

Неточные вычисления

Внутри JavaScript число представлено в виде 64-битного формата IEEE-754. Для хранения числа используется 64 бита: 52 из них используется для хранения цифр, 11 из них для хранения положения десятичной точки (если число целое, то хранится 0), и один бит отведён на хранение знака.

Если число слишком большое, оно переполнит 64-битное хранилище, JavaScript вернёт бесконечность:

Наиболее часто встречающаяся ошибка при работе с числами в JavaScript – это потеря точности.

Посмотрите на это (неверное!) сравнение:

Да-да, сумма и не равна .

Странно! Что тогда, если не ?

Но почему это происходит?

Число хранится в памяти в бинарной форме, как последовательность бит – единиц и нулей. Но дроби, такие как , , которые выглядят довольно просто в десятичной системе счисления, на самом деле являются бесконечной дробью в двоичной форме.

Другими словами, что такое ? Это единица делённая на десять — , одна десятая. В десятичной системе счисления такие числа легко представимы, по сравнению с одной третьей: , которая становится бесконечной дробью .

Деление на гарантированно хорошо работает в десятичной системе, но деление на – нет. По той же причине и в двоичной системе счисления, деление на обязательно сработает, а становится бесконечной дробью.

В JavaScript нет возможности для хранения точных значений 0.1 или 0.2, используя двоичную систему, точно также, как нет возможности хранить одну третью в десятичной системе счисления.

Числовой формат IEEE-754 решает эту проблему путём округления до ближайшего возможного числа. Правила округления обычно не позволяют нам увидеть эту «крошечную потерю точности», но она существует.

Пример:

И когда мы суммируем 2 числа, их «неточности» тоже суммируются.

Вот почему – это не совсем .

Не только в JavaScript

Справедливости ради заметим, что ошибка в точности вычислений для чисел с плавающей точкой сохраняется в любом другом языке, где используется формат IEEE 754, включая PHP, Java, C, Perl, Ruby.

Можно ли обойти проблему? Конечно, наиболее надёжный способ — это округлить результат используя метод toFixed(n):

Также можно временно умножить число на 100 (или на большее), чтобы привести его к целому, выполнить математические действия, а после разделить обратно. Суммируя целые числа, мы уменьшаем погрешность, но она все равно появляется при финальном делении:

Таким образом, метод умножения/деления уменьшает погрешность, но полностью её не решает.

Забавный пример

Попробуйте выполнить его:

Причина та же – потеря точности. Из 64 бит, отведённых на число, сами цифры числа занимают до 52 бит, остальные 11 бит хранят позицию десятичной точки и один бит – знак. Так что если 52 бит не хватает на цифры, то при записи пропадут младшие разряды.

Интерпретатор не выдаст ошибку, но в результате получится «не совсем то число», что мы и видим в примере выше. Как говорится: «как смог, так записал».

Два нуля

Другим забавным следствием внутреннего представления чисел является наличие двух нулей: и .

Все потому, что знак представлен отдельным битом, так что, любое число может быть положительным и отрицательным, включая нуль.

В большинстве случаев это поведение незаметно, так как операторы в JavaScript воспринимают их одинаковыми.

Выбор способа округления

Существует несколько способов округления в зависимости от способа применения результата: округление к меньшему/ большему, округление к меньшему/ большему по модулю, округление к ближайшему целому, округление к ближайшему чётному и т. д… Округление к ближайшему целому, в свою очередь, можно делать по-разному в зависимости от того, какой результат должен получиться, если дробная часть равна 0,5. Я буду рассматривать округление к ближайшему целому, причём 0,5 будет округляться в большую (по модулю) сторону.

Требования к корректной реализации Round() заключаются в следующем:

  • правильно округляет до ближайшего целого все конечные числа;
  • поддерживает специальные значения (NaN, Inf, -0), возвращая их без изменений.

Я буду использовать следующие тестовые примеры для проверки корректности, в каждой паре содержатся исходное значение и предполагаемый результат выполнения функции Round():

В этом списке есть обычные числа, специальные значения и некоторые граничные случаи, с которыми простым алгоритмам сложно справиться

Обратите внимание, что, поскольку мы используем float, мы не можем использовать число 0,49999999999999999 в качестве ближайшего к 0,5, так как из-за ограниченной точности float это число в точности равно 0,5. Вместо этого я использую 0,49999999999999994

Реализации, предложенные в закрытом тикете, явно не были проверены на подобных данных, часто не работали даже те из них, которые были предложены известными людьми. Это лишний раз доказывает, насколько сложно написать Round().

int(f + 0.5)

Первая реализация, предложенная rsc, выглядела следующим образом:

Она некорректно работает с особыми значениями, отрицательными числами, числами больше math.MaxInt64 и числами, близкими к 0,5:

Floor() or Ceil()

Второй предложенный вариант учитывал отрицательные числа:

однако продолжал некорректно работать в некоторых случаях:

Первые два теста не проходят, потому что результат разности n — 0,5 равен в точности -1,0, тогда как мы ожидаем получить что-то точно большее, чем -1,0. Если посмотреть на , можно понять, как решить эту проблему.

Самое интересное, что эта ошибка не является такой уж редкой. До версии 6 точно такая же присутствовала в Java. Хорошо, что с тех пор реализация улучшилась.

int и Copysign

В третьем предложении от minux была предпринята другая попытка решить проблему отрицательных чисел:

И этот вариант всё равно ломает тесты:

Как видно, часть тестов стала проходить, однако другие начали падать. Была предпринята попытка улучшить этот алгоритм:

Однако и она провалилась:

Этот вариант выглядит лучше остальных, но и он некорректно обрабатывает особые значения и большие числа. Первую проблему можно решить с помощью дополнительных условий, но со второй справиться не так просто.

Мы рассмотрели уже четыре варианта, и в каждом из них нашлись изъяны. Настало время посмотреть, как Round() реализуют авторы различных пакетов.

Kubernetes

Kubernetes 1.7 содержит реализацию:

Она ломает следующие тесты:

Судя по тому, что функция возвращает int32, она не предназначена для работы с большими числами. Однако она некорректно работает и с числами, которые близки к 0,5.

Как проверить, активирована ли Windows 10?

Округление при работе с числами ограниченной точности

Реальные физические величины всегда измеряются с некоторой конечной точностью, которая зависит от приборов и методов измерения и оценивается максимальным относительным или абсолютным отклонением неизвестного истинного значения от измеренного, что в десятичном представлении значения соответствует либо определённому числу значащих цифр, либо определённой позиции в записи числа, все цифры после (правее) которой являются незначащими (лежат в пределах погрешности измерения). Сами измеренные параметры записываются с таким числом знаков, чтобы все цифры были надёжными, возможно, последняя — сомнительной. Погрешность при математических операциях с числами ограниченной точности сохраняется и изменяется по известным математическим законам, поэтому когда в дальнейших вычислениях возникают промежуточные значения и результаты с больши́м числом цифр, из этих цифр только часть являются значимыми. Остальные цифры, присутствуя в значениях, фактически не отражают никакой физической реальности и лишь отнимают время на вычисления. Вследствие этого промежуточные значения и результаты при вычислениях с ограниченной точностью округляют до того количества знаков, которое отражает реальную точность полученных значений. На практике обычно рекомендуется при длинных «цепочных» ручных вычислениях сохранять в промежуточных значениях на одну цифру больше. При использовании компьютера промежуточные округления в научно-технических приложениях чаще всего теряют смысл, и округляется только результат.

Так, например, если задана сила 5815 гс с точностью до грамма силы и длина плеча 1,40 м с точностью до сантиметра, то момент силы в кгс по формуле M=(mg)⋅h{\displaystyle M=(mg)\cdot h}, в случае формального расчёта со всеми знаками, окажется равным: 5,815 кгс • 1,4 м = 8,141 кгс•м. Однако если учесть погрешность измерения, то мы получим, что предельная относительная погрешность первого значения составляет 1/5815 ≈ 1,7•10−4, второго — 1/140 ≈ 7,1•10−3, относительная погрешность результата по правилу погрешности операции умножения (при умножении приближённых величин относительные погрешности складываются) составит 7,3•10−3, что соответствует максимальной абсолютной погрешности результата ±0,059 кгс•м! То есть в реальности, с учётом погрешности, результат может составлять от 8,082 до 8,200 кгс•м, таким образом, в рассчитанном значении 8,141 кгс•м полностью надёжной является только первая цифра, даже вторая — уже сомнительна! Корректным будет округление результата вычислений до первой сомнительной цифры, то есть до десятых: 8,1 кгс•м, или, при необходимости более точного указания рамок погрешности, представить его в виде, округлённом до одного-двух знаков после запятой с указанием погрешности: 8,14 ± 0,06 кгс•м.

Округление рассчитанного значения погрешности

Обычно в окончательном значении рассчитанной погрешности оставляют только первые одну-две значащие цифры. По одному из применяемых правил, если значение погрешности начинается с цифр 1 или 2(по другому правилу — 1, 2 или 3), то в нём сохраняют две значащих цифры, в остальных случаях — одну, например: 0,13; 0,26; 0,3; 0,8. То есть каждая декада возможных значений округляемой погрешности разделена на две части. Недостаток этого правила состоит в том, что относительная погрешность округления изменяется значительным скачком при переходе от числа 0,29 к числу 0,3. Для устранения этого предлагается каждую декаду возможных значений погрешности делить на три части с менее резким изменением шага округления. Тогда ряд разрешённых к употреблению округлённых значений погрешности получает вид:

  • 0,10; 0,12; 0,14; 0,16; 0,18;
  • 0,20; 0,25; 0,30; 0,35; 0,40; 0,45;
  • 0,5; 0,6; 0,7; 0,8; 0,9; 1,0.

Однако при использовании такого правила последние цифры самого результата, оставляемые после округления, также должны соответствовать приведённому ряду.

Пересчёт значений физических величин

Пересчёт значения физической величины из одной системы единиц в другую должен производиться с сохранением точности исходного значения. Для этого исходное значение в одних единицах следует умножить (разделить) на переводной коэффициент, часто содержащий большое количество значащих цифр, и округлить полученный результат до количества значащих цифр, обеспечивающего точность исходного значения. Например, при пересчёте значения силы 96,3 тс в значение, выраженное в килоньютонах (кН), следует умножить исходное значение на переводной коэффициент 9,80665 (1 тс = 9,80665 кН). В результате получается значение 944,380395 кН, которое необходимо округлить до трёх значащих цифр. Вместо 96,3 тс получаем 944 кН.

Округление

Одна из часто используемых операций при работе с числами – это округление.

В JavaScript есть несколько встроенных функций для работы с округлением:

Округление в меньшую сторону: становится , а — .
Округление в большую сторону: становится , а — .
Округление до ближайшего целого: становится , — , а — .
(не поддерживается в Internet Explorer)
Производит удаление дробной части без округления: становится , а — .

Ниже представлена таблица с различиями между функциями округления:

Эти функции охватывают все возможные способы обработки десятичной части. Что если нам надо округлить число до количества цифр в дробной части?

Например, у нас есть и мы хотим округлить число до 2-х знаков после запятой, оставить только .

Есть два пути решения:

Умножить и разделить.
Например, чтобы округлить число до второго знака после запятой, мы можем умножить число на , вызвать функцию округления и разделить обратно.

Метод toFixed(n) округляет число до знаков после запятой и возвращает строковое представление результата.

Округляет значение до ближайшего числа, как в большую, так и в меньшую сторону, аналогично методу :

Обратите внимание, что результатом является строка. Если десятичная часть короче, чем необходима, будут добавлены нули в конец строки:

Мы можем преобразовать полученное значение в число, используя унарный оператор или , пример с унарным оператором: .

Округление чисел

Для нахождения приближенного значения применяется такое действие как округление чисел.

Слово «округление» говорит само за себя. Округлить число значит сделать его круглым. Круглым называется число, которое оканчивается нулём. Например, следующие числа являются круглыми:

10, 20, 30, 100, 300, 700, 1000

Любое число можно сделать круглым. Процедуру, при которой число делают круглым, называют округлением числá.

Мы уже занимались «округлением» чисел, когда делили большие числа. Напомним, что для этого мы оставляли без изменения цифру, образующую старший разряд, а остальные цифры заменяли нулями. Но это были лишь наброски, которые мы делали для облегчения деления. Своего рода лайфхак. По факту, это даже не являлось округлением чисел. Именно поэтому в начале данного абзаца мы взяли слово округление в кавычки.

На самом деле, суть округления заключается в том, чтобы найти ближайшее значение от исходного. При этом, число может быть округлено до определённого разряда — до разряда десятков, разряда сотен, разряда тысяч.

Рассмотрим простой пример на округление. Дано число 17. Требуется округлить его до разряда десятков.

Не забегая вперёд попробуем понять, что означает «округлить до разряда десятков». Когда говорят округлить число 17, то надо понимать, что от нас требуют найти ближайшее круглое число от числá 17. Причём в ходе этого поиска возможно изменения коснутся и той цифры, которая располагается в разряде десятков числá 17 (т.е цифры 1).

Предстáвим числа от 10 до 20 с помощью следующего рисунка:

На рисунке видно, что для числá 17 ближайшее круглое число это число 20. Значит ответ к задаче таким и будет: «17 приближённо равно 20″

17 ≈ 20

Мы нашли приближённое значение для 17, то есть округлили его до разряда десятков. Видно, что после округления в разряде десятков появилась новая цифра 2.

Попробуем найти приближённое число для числа 12. Для этого снова предстáвим числа от 10 до 20 с помощью рисунка:

На рисунке видно, что ближайшее круглое число для 12 это число 10. Значит ответ к задаче таким и будет: 12 приближённо равно 10

12 ≈ 10

Мы нашли приближённое значение для 12, то есть округлили его до разряда десятков. В этот раз цифра 1, которая стояла в разряде десятков в числе 12, не пострадала от округления. Почему так получилось мы расскажем позже.

Попробуем найти ближайшее число для числá 15. Снова предстáвим числа от 10 до 20 с помощью рисунка:

На рисунке видно, что число 15 одинаково удалено от круглых чисел 10 и 20. Возникает вопрос: которое из этих круглых чисел будет приближённым значением для числа 15? Для таких случаев условились принимать бóльшее число за приближённое. 20 больше чем 10, поэтому приближённое значение для 15 будет число 20

15 ≈ 20

Округлять можно и большие числа. Естественно, для них делать рисунки и изображать числа не представляется возможным. Для них существует свой способ. Например, округлим число 1456 до разряда десятков.

Итак, мы должны округлить 1456 до разряда десятков. Разряд десятков начинается на пятёрке:

Теперь о существовании первых цифр 1 и 4 временно забываем. Остается число 56

Теперь смотрим, какое круглое число находится ближе к числу 56. Очевидно, что ближайшее круглое число для 56 это число 60. Значит заменяем число 56 на число 60

Значит при округлении числа 1456 до разряда десятков полýчим 1460

1456 ≈ 1460

Видно, что после округления числа 1456 до разряда десятков, изменения коснулись и самогó разряда десятков. В новом полученном числе в разряде десятков теперь располагается цифра 6, а не 5.

Округлять числа можно не только до разряда десятков. Округлять число можно до разряда сотен, тысяч, десятков тысяч и так далее.

После того, как станóвится ясно, что округление это ни что иное как поиск ближáйшего числá, можно применять готовые правила, которые значительно облегчают округление чисел.

Заключение

В этой статье я рассказывал в основном об округлении к меньшему по модулю, но есть . В некоторых случаях подходят именно они, и я оставлю читателю возможность изучить их и попробовать реализовать на Go. Но я надеюсь, что теперь вам стало понятно, как устроено округление в Go и как нужно тестировать реализации округления.

Думаю, команда Go приняла правильное решение, добавив функцию Round() в стандартную библиотеку. Без этого мы бы продолжали пользоваться различными некорректными реализациями.

Надеюсь, теперь вам стало ясно, что при работе с float есть много подводных камней, про которые порой забывают даже эксперты. Легко придумать или скопировать откуда-то однострочную реализацию, но сложно написать действительно корректную. Неудивительно, что корректно работающее округление появилось лишь в шестой мажорной версии Java (через 15 лет, прошедших с релиза Java 1.0 до выхода Java 7), и я рад, что Go прошёл этот путь быстрее.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock
detector