Закрыть

Для эффективной работы на сайте используются cookie и обработка персональных данных. Пользуясь этим сайтом, вы соглашаетесь с правилами использования сайта. Подробнее

Цитата дня

Vivazzi.ru

Личный сайт Мальцева Артема

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

Дейл Карнеги

Округление в python

7 апреля 2016 г. 20: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 округление до верха (в большую сторону) 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 ), что round() работает по принципу банковского округления, но, как оказалось, это не так. Спасибо безымянному гостю, который в комментариях открыл мне глаза на это дело.

Само банковское округление - очень полезное для расчётов. Банковское (или бухгалтерское) округление позволяет уменьшить погрешности при работе с большим массивом данных. Обычное (или арифметическое) округление даёт нарастающую погрешность из-за того, что для округления в меньшую сторону на конце должны быть цифры: 1, 2, 3, 4 - всего 4 цифр, а в большую: 5, 6, 7, 8, 9 - всего 5 цифр. Неравное количество цифр и вызывают нарастающую погрешность в вычислениях. А банковское округление работает по статистическим законам: вероятность того, что перед пятёркой окажется чётное или нечётное число для большинства случаев (к примеру, бухгалтерские расчёты) примерно одинаковая, поэтому округление происходит к ближайшему чётному, то есть 2,5 → 2, 3,5 → 4. - такой принцип уменьшает погрешность.

Но функция round() в python выполняет арифметическое округление! Доказательство тому официальные источники документации python:

И вpython 2 и в python 3 round() выполняет арифметическое округление, а разный результат получается из-за неточности представления типа float. Официальный комментарий по этому поводу (взято из ссылок выше):

The behavior of round() for floats can be surprising: for example, round(2.675, 2) gives 2.67 instead of the expected 2.68. This is not a bug: it’s a result of the fact that most decimal fractions can’t be represented exactly as a float. See Floating Point Arithmetic : Issues and Limitations for more information.
Перевод: Поведение round() для float может быть неожиданным: например, round(2.675, 2) дает 2.67 вместо ожидаемого 2.68. Это не ошибка: это результат того, что большинство десятичных дробей не может быть представлено точно как float. См. Арифметику с плавающей точкой : проблемы и ограничения для получения дополнительной информации.

Основной пример, показывающий принцип работы round() в python приведён выше в начале статьи.

Но напоследок приведу ещё один наглядный пример того, что значения python round() и банковского округления различны:

Пример python round() банковское округление
round(2.05, 1) 2.0 2.0
round(2.15, 1) 2.1 2.2
round(2.25, 1) 2.3 2.2
round(2.35, 1) 2.4 2.4
round(2.45, 1) 2.5 2.4
round(2.55, 1) 2.5 2.6
round(2.65, 1) 2.6 2.6
round(2.75, 1) 2.8 2.8
round(2.85, 1) 2.9 2.8
round(2.95, 1) 3.0 3.0

Жирным выделил несовпадающие значения, которые ещё раз доказывают, что round() не работает по банковскому округлению.

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

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

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

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

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

Автор статьи

Права на использование данной статьи, расположенной на настоящей странице http://vivazzi.ru/it/round-python/:

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

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

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

Вам нужно саморазвиваться или вы хотите зарабатывать деньги?

Или вы ищите хорошие IT сервисы или книги? Сохраните свое время и взгляните на мою подборку рекомендаций, которыми постоянно пользуюсь.
Посмотреть рекомендации

Комментариев: 2

Гость
Гость

26.02.2018 4:14 #

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

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

Ответить

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

26.02.2018 23:17 #

Гость, спасибо за ваш комментарий!
Миф о банковском округлении разрушен, статью подправил.

Ответить

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

Чтобы оставить комментарий от своего имени войдите или зарегистрируйтесь обычным способом или через социальные сети:

Отправить

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

Попробуйте