Округление в python
8 апреля 2016 г. 0:05
Округление в python осуществляется функцией round(number, ndigits)
, где number
- округляемое число, а ndigits
- количество знаков после запятой. Например:
round(2.137, 2) # = 2.14
Иногда округление может дать неожиданный результат, например:
round(2.45, 2) # = 2.5 round(2.55, 2) # = 2.5, а не 2.6!
Это связано с неточностью представления типа float
(см. Арифметика с плавающей точкой). Так как в компьютере числа записываются в двоичном виде, то приблизительно можно посмотреть, как хранятся числа 2.45 и 2.55, с помощью строкового представления чисел в python. Выведем данные числа с точностью до 30 знаков после запятой:
>>> '%0.30f' % 2.45 '2.450000000000000177635683940025' >>> '%0.30f' % 2.55 '2.549999999999999822364316059975'
Как видите, округляя значение 2.549999999999999822364316059975
до 1 знака после запятой, по правилам арифметического округления получим 2.5
Имейте ввиду, что в python 3 (в отличии от python 2) используется банковское округление (что это см. ниже в разделе "Банковское округление в round()").
В python округление до верха (в большую сторону) math.ceil(x)
, а округление до низа (в меньшую сторону) math.floor(x)
, например:
import math math.ceil(2.3) # = 3.0 - округление до верха math.floor(2.7) # = 2.0 - округление до низа
Чтобы получить целое число, нужно просто привести полученный результат в int:
round(2.6) # = 3.0 int(round(2.6)) # = 3
Чтобы просто отбросить знаки после запятой, можно сделать так:
int(2.6) # = 2 , что эквивалентно int(math.floor(2.6))
Банковское округление в round()
Очень много идёт дискуссий (pythonworld, stackoverflow, форум linux.org.ru и др.) на тему, какое же всё-таки округление в python арифметическое или банковское (по другому ещё называют Гауссово округление)?
Оказывается в python 2 используется арифметическое округление, а в python 3 - банковское! Спасибо Дмитрию, внёсшему ясность в комментариях, по какому правилу идёт округление в разных python, благодаря подробному примеру и указанию на авторитетный источник.
Банковское (или бухгалтерское) округление позволяет уменьшить погрешности при работе с большим массивом данных. Обычное (или арифметическое) округление даёт нарастающую погрешность из-за того, что для округления в меньшую сторону на конце должны быть цифры: 1, 2, 3, 4 - всего 4 цифр, а в большую: 5, 6, 7, 8, 9 - всего 5 цифр. Неравное количество цифр при большом количестве вычислений и вызывают нарастающую погрешность.
При банковском округлении осуществляется округление к ближайшему чётному, то есть 2,5 → 2
, 3,5 → 4
. Таким образом вероятность того, что перед пятёркой окажется чётное или нечётное число для большинства случаев (к примеру, бухгалтерские расчёты) примерно одинаковая, поэтому такой принцип уменьшает погрешность.
Здесь вы можете увидеть подробности округления в официальных источниках документации python:
- Для python 2: https://docs.python.org/2/library/functions.html#round
- Для python 3: https://docs.python.org/3/library/functions.html#round
Обратите внимание, что документации разных версий python отличаются, а точнее в python 3 добавлено:
For the built-in types supporting round(), values are rounded to the closest multiple of 10 to the power minus ndigits; if two multiples are equally close, rounding is done toward the even choice (so, for example, both round(0.5) and round(-0.5) are 0, and round(1.5) is 2).
"if two multiples are equally close, rounding is done toward the even choice" (перев.: Округление делается до ближайшего четного) - это и есть банковское округление.
Но напоследок приведу пример, наглядно демонстрирующий разницу работы функции round() в различных версиях python и с учётом неточности представления типа float
:
Пример | round() в python 2 | round() в python 3 | банковское округление |
---|---|---|---|
round(2.05, 1) | 2.0 | 2.0 | 2.0 |
round(2.15, 1) | 2.1 | 2.1 | 2.2 |
round(2.25, 1) | 2.3 | 2.2 | 2.2 |
round(2.35, 1) | 2.4 | 2.4 | 2.4 |
round(2.45, 1) | 2.5 | 2.5 | 2.4 |
round(2.55, 1) | 2.5 | 2.5 | 2.6 |
round(2.65, 1) | 2.6 | 2.6 | 2.6 |
round(2.75, 1) | 2.8 | 2.8 | 2.8 |
round(2.85, 1) | 2.9 | 2.9 | 2.8 |
round(2.95, 1) | 3.0 | 3.0 | 3.0 |
Жирным выделил отличающиеся значения выполнения функции round().
Казалось бы в примере с round(2.15, 1)
результат для python 3 должен быть 2.2
, потому как python 3 работает по банковскому округлению, но правильное значение 2.1
, так как значение 2.1
в машинном представлении не точное и выглядит для, к примеру, 60 знаков после запятой следующим образом:
>>> '%0.60f' % 2.15 '2.149999999999999911182158029987476766109466552734375000000000'
Отсюда видно, что по правилам обычного арифметического округления получаем 2.1
.
Но для примера round(2.25, 1)
60 знаков после запятой выглядят следующим образом:
>>> '%0.60f' % 2.25 '2.250000000000000000000000000000000000000000000000000000000000'
Вот здесь-то и возникает спорный момент по способу округления. Так для python 2 получаем 2.3
- арифметическое округление.
А для python 3 получаем 2.2
, что соответствует правилам банковского округления.
Материалы по теме:
Похожие статьи:
Представляю вашему вниманию книгу, написанную моим близким другом Максимом Макуриным: Секреты эффективного управления ассортиментом.
Книга предназначается для широкого круга читателей и, по мнению автора, будет полезна специалистам отдела закупок и логистики, категорийным и финансовым менеджерам, менеджерам по продажам, аналитикам, руководителям и директорам, в компетенции которых принятие решений по управлению ассортиментом.
Комментарии: 8
26.02.2018 9:14 #
Заблуждение ! В python обычное математическое округление. Описанное поведение связано с неточностью представления десятичных чисел во float .
Ответить
27.02.2018 4:17 #
Гость, спасибо за ваш комментарий!
Миф о банковском округлении разрушен, статью подправил.
Обновлено 10.06.2018: Нет, миф всё-таки не разрушен, см. комментарии ниже https://vivazzi.pro/it/round-python/#comment_154
Ответить
09.06.2018 21:16 #
В python3 именно банковское округление. Но и неточности float тоже присутствуют.
Если Вы считаете что в python3 арифметическое округление, то объясните пожалуйста это:
Ответить
10.06.2018 4:01 #
Да, согласен в python 2 и python 3 в примере
round(2.5)
дают разные результаты (2 и 3 соответственно) .Хорошо, Дмитрий, приведите, пожалуйста, официальные источники, как всё-таки идёт округление в python. Пока из авторитетных источников я нашёл только это https://docs.python.org/2/library/functions.html#round (для python 2) и https://docs.python.org/3/library/functions.html#round (для python 3) - и в них не говорится о банковском округлении.
Ответить
11.06.2018 6:56 #
Собственно в py3 документации по Вашей ссылке об этом и сказано :
Ответить
11.06.2018 11:26 #
Дмитрий, большое спасибо за подробное объяснение, как всё-таки идёт округление в python!
Ответить
22.12.2020 22:47 #
Очень жаль, что в банках (российских?) не используется "банковское округление". Приходится писать собственные функции округления, что нонсенс для такого продвинутого языка.
Ответить
24.12.2020 10:17 #
Это весьма странно, что в каких-то российских банках не используется банковское округление. Ведь этому, как я понимаю, ещё в университетах учат на экономических специальностях . Видимо, некоторые банки хотят побольше насобирать копеек, ведь проведя миллионы операций будет весьма ощутимая разница. Я даже приводил пример в нашем проекте https://vivazzi.pro/viva-tm/advantages/#11-tochnost-vychisleni y По хорошему надо обратиться в руководство банка с требованием изменить логику округления чисел в пользу банковского округления.
Ответить