Округление в 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 отличаются, а точнее в 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, что соответствует правилам банковского округления.

Материалы по теме:

Оцените статью

5 из 5 (всего 16 оценок)

captcha
Отмеченные звёздочкой поля ( * ) являются обязательными для заполнения.

Спасибо за ваш отзыв!

После нажатия кнопки "Отправить" ваше сообщение будет доставлено мне на почту.

Автор статьи

Артём Мальцев

Веб-разработчик, владеющий знаниями языка программирования Python, фреймворка Django, системы управления содержимым сайта Django CMS, платформы для создания интернет-магазина Django Shop и многих различных приложений, использующих эти технологии.

Права на использование материала, расположенного на этой странице https://vivazzi.pro/ru/it/round-python/:

Разрешается копировать материал с указанием её автора и ссылки на оригинал без использования параметра rel="nofollow" в теге <a>. Использование:

Автор статьи: Артём Мальцев
Ссылка на статью: <a href="https://vivazzi.pro/ru/it/round-python/">https://vivazzi.pro/ru/it/round-python/</a>

Больше: Правила использования сайта

Представляю вашему вниманию книгу, написанную моим близким другом Максимом Макуриным: Секреты эффективного управления ассортиментом.

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

Комментарии: 8

Гость
Гость

26.02.2018 9:14 #

Заблуждение ! В python обычное математическое округление. Описанное поведение связано с неточностью представления десятичных чисел во float .

>>> '%0.30f' % 2.45
'2.450000000000000177635683940025'
>>> '%0.30f' % 2.55
'2.549999999999999822364316059975'

Ответить

Артём Мальцев
Артём Мальцев автор

27.02.2018 4:17 #

Гость, спасибо за ваш комментарий!
Миф о банковском округлении разрушен, статью подправил.
Обновлено 10.06.2018: Нет, миф всё-таки не разрушен, см. комментарии ниже https://vivazzi.pro/it/round-python/#comment_154

Ответить

Дмитрий
Дмитрий

09.06.2018 21:16 #

В python3 именно банковское округление. Но и неточности float тоже присутствуют.
Если Вы считаете что в python3 арифметическое округление, то объясните пожалуйста это:

>>> round(2.5)
2
>>> '%0.100f' % 2.5
'2.5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
>>>

Ответить

Артём Мальцев
Артём Мальцев автор

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 документации по Вашей ссылке об этом и сказано :

if two multiples are equally close, rounding is done toward the even choic e Округление делается до ближайшего четного - это и есть банковское округление . P.S. Чтобы выяснить, какое округление используется, нужно брать числа, которые не имеют неточностей и стоят ровно между двух чисел. Тогда начинает работать правило: либо это арифметическое (py2) - округляем вверх, либо это банковское (py3) - округляем до ближайшего четного. А если число не стоит ровно между двух чисел (например имеет неточности float), то и в py2 и в 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 По хорошему надо обратиться в руководство банка с требованием изменить логику округления чисел в пользу банковского округления.

Ответить

Вы можете оставить комментарий как незарегистрированный пользователь.

Но зарегистрировавшись, вы сможете:

  • получать оповещения об ответах
  • просматривать свои комментарии
  • иметь возможность использовать все функции разработанных сервисов

Для комментирования от своего имени войдите или зарегистрируйтесь на сайте Vuspace

Отправить

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

Попробуйте

Выберите валюту для отображения денежных единиц