Округление в Python: выбираем лучший способ
Отсекаем хвосты числовым змеям без потерь в точности.
Иллюстрация: Катя Павловская для Skillbox Media
Когда работаешь с десятичными дробями в коде, часто получаются монструозные числа с кучей знаков после запятой. В этой статье научимся сокращать значения так, чтобы не потерять в точности и не внести погрешности.
6 способов округления в Python
Функция round() в Python — стандартный способ
В Python есть встроенная функция для округления чисел. В общем виде она выглядит так: round(number, digits). В качестве первого аргумента (number) передаём дробное число, а во втором (digits) указываем количество чисел после запятой. Второй аргумент по умолчанию равен нулю.
Важно отметить, что алгоритм вычисления функции round() различается в разных версиях языка. В Python 2 за основу взяты классические правила арифметики. То есть 1, 2, 3, 4 после запятой ведут к округлению в меньшую сторону, а 5, 6, 7, 8, и 9 — в большую.
Например:
- 7,6 → 8 — округление в большую сторону.
- 7,4 → 7 — округление в меньшую сторону.
В Python 3 используется так называемый «банковский» метод, то есть округление до ближайшего чётного числа:
- 3,5 → 4.
- 6,5 → 6.
В этой статье мы будем использовать Python 3. Вот как работает округление в этой версии с помощью функции round():
Видно, что round() привела число к ближайшему чётному, и число 7,5 округлилось до 8. В последнем случае мы задали точность вычислений и оставили только два знака после запятой. С отрицательными числами всё работает так же:
Чтобы получить целое значение, функция round() приводит результат к типу int. Именно поэтому 7,7 превращается в 8, а не в 8,0.
Функция int() в Python — быстрый и грубый способ
Есть и более быстрый способ округлить число в Python — полностью отбросить дробную часть. Чтобы это сделать, надо привести дробное число к целому с помощью встроенной функции int(). Такой способ работает безотказно и не требует импорта дополнительных модулей. Посмотрим на примеры:
Во всех примерах выше мы получаем число 7 после округления. Теперь провернём то же самое, но для отрицательных значений:
Ничего не поменялось, и Python всё равно отбрасывает всё, что находится после запятой. Это очень грубый подход, который противоречит правилам арифметического округления. Но можно добавить точности с помощью простого условия: прибавим к числу 0,5, если оно больше нуля, а если меньше — −0,5:
В этом случае округление будет работать правильно, но нам пришлось написать дополнительную функцию. В Python есть более быстрые и удобные способы.
Модуль math в Python — когда важна точность
Если хотите точности без написания дополнительных алгоритмов, можно подключить встроенную в Python библиотеку math. В ней есть функции, которые позволяют округлить число быстро и без программных костылей.
Вот эти функции:
- ceil() — округление в большую сторону;
- floor() — округление в меньшую сторону;
- trunc() — отбрасывание дробной части.
Дальше мы расскажем о каждой функции подробнее. Но сначала — импортируем модуль math в наш проект. Для этого пропишем команду import math в начале файла. Если пропустить этот шаг, Python просто не поймёт, как ему исполнять эти функции.
math.ceil
Функция ceil() округляет результат в большую сторону. Например, число 25,5 находится между 25 и 26, поэтому алгоритм автоматически округлит его до 26:
Этот же принцип работает и с отрицательными числами:
В Python 3 функция math.ceil возвращает целое число (int), а в Python 2 — число с плавающей точкой (float).
math.floor
Для округления в меньшую сторону используют функцию floor(). Принцип её работы идентичен ceil(), только при сравнении Python пойдёт вниз:
Всё то же самое происходит и с отрицательными числами. Python смотрит на соседние целые числа, выбирает, какое из них ближе и округляет до него. В случае с −25 меньшим числом будет −26:
math.trunc
Эта функция из математического модуля Python просто отбрасывает все числа после запятой, оставляя только целую часть:
Это очень похоже на округление с помощью int(). Поэтому, если вам нужен быстрый и грубый способ избавиться от дроби, лучше пользоваться именно ей. Не стоит подключать в проект целый модуль ради одной функции, если, конечно, вы не любитель палить из пушки по воробьям :)
Модуль decimal в Python — ещё больше точности
Python не всегда точно обрабатывает дробные числа. В этом можно убедиться на простом примере:
Должно получиться 0,3, но вместо этого появилось много нулей после запятой. Так получается из-за перевода десятичных дробей в двоичную систему в памяти компьютера. Эта же особенность иногда приводит к ошибкам при округлении:
В первом случае Python округлил в меньшую сторону, а во втором — в большую, хотя в обеих дробях стоит одна и та же пятёрка на конце. Если хотите получать более предсказуемый результат, можно использовать модуль decimal.
Для начала импортируем модуль командой from decimal import *. После этого создадим объект числа с плавающей точкой с помощью класса Decimal.
Ошибок при вычислении уже не будет:
Для округления в Decimal есть метод quantize(). Но, чтобы он нормально работал, ему нужно показать, как именно форматировать число. Для этого передадим ему в качестве аргумента ещё один объект Decimal с числом-шаблоном:
Видим, что число 1.000 показывает алгоритму, сколько именно знаков нужно оставить после запятой.
Теперь вернёмся к первому примеру, где метод round() округлял похожие числа по-разному. С помощью Decimal, получим более прогнозируемый результат:
Если в программе важна высокая точность при округлении чисел, то лучше использовать модуль decimal. Код получится немного сложнее, но это убережёт от получения непредсказуемых результатов и ошибок в подсчётах.
Что в итоге
- Самый простой способ округления — отбросить дробную часть с помощью метода int(). Однако этот подход довольно грубый и не подходит для решения задач, в которых важна высокая точность.
- Для округления в Python предусмотрена нативная функция round(), но алгоритм вычислений различается в зависимости от версии языка программирования. С этим надо быть внимательнее.
- В модуле math содержатся уже готовые функции ceil(), floor() и trunc(). С ними проще работать, а результат получается более предсказуемым.
- Из-за особенностей компьютерных вычислений Python не всегда точно обрабатывает десятичные дроби. Чтобы избежать связанных с этим ошибок, используйте модуль decimal.
Больше интересного про код — в нашем телеграм-канале. Подписывайтесь!