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

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

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

Способы округления чисел

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

Если используется стандартная библиотека math, то в начале кода её необходимо подключить. Сделать это можно, например, с помощью инструкции: import math.

math.ceil() — округление чисел в большую сторону

Функция получила своё имя от термина «ceiling», который используется в математике для описания числа, которое больше или равно заданному.

Любая дробь находится в целочисленном интервале, например, 1.2 лежит между 1 и 2. Функция ceil() определяет, какая из границ интервала наибольшая и записывает её в результат округления.

Пример:

math.ceil(5.15) # = 6
math.ceil(6.666) # = 7
math.ceil(5) # = 5
Важно помнить, что функция определяет наибольшее число с учётом знака. То есть результатом округления числа -0.9 будет 0, а не -1.

math.floor() — округление чисел в меньшую сторону

Функция округляет дробное число до ближайшего целого, которое меньше или равно исходному. Работает аналогично функции ceil(), но с округлением в противоположную сторону.

Пример:

math.floor(7.9) # = 7
math.floor(9.999) # = 9
math.floor(-6.1) # = -7

math.trunc() — отбрасывание дробной части

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

Примеры:

math.trunc(5.51) # = 5
math.trunc(-6.99) # = -6

Избавиться от дробной части можно с помощью обычного преобразования числа к типу int. Такой способ полностью эквивалентен использованию trunc().

Примеры:

int(5.51) # = 5
int(-6.99) # = -6

Нормальное округление

Python позволяет реализовать нормальное арифметическое округление, использовав функцию преобразования к типу int.

И хотя int() работает по другому алгоритму, результат её использования для положительных чисел полностью аналогичен выводу функции floor(), которая округляет числа «вниз». Для отрицательных аналогичен функции ceil().

Примеры:

math.floor(9.999) # = 9
int(9.999) # = 9
math.ceil(-9.999) # = -9
int(-9.999) # = -9

Чтобы с помощью функции int() округлить число по математическим правилам, необходимо добавить к нему 0.5, если оно положительное, и -0.5, если оно отрицательное.

Тогда операция принимает такой вид: int(num + (0.5 if num > 0 else -0.5)). Чтобы каждый раз не писать условие, удобно сделать отдельную функцию:

def int_r(num):
    num = int(num + (0.5 if num > 0 else -0.5))
    return num

Функция работает также, как стандартная функция округление во второй версии Python (арифметическое округление).

Примеры:

int_r(11.5) # = 12
int_r(11.4) # = 11
int_r(-0.991) # = -1
int_r(1.391) # = 1

round() — округление чисел

round() — стандартная функция округления в языке Python. Она не всегда работает так, как ожидается, а её алгоритм различается в разных версиях Python.

В Python 2

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

Увеличение погрешности вызвано неравным количеством цифр, определяющих, в какую сторону округлять. Всего 4 цифры на конце приводят к округлению «вниз», и 5 цифр к округлению «вверх».

Помимо этого, могут быть неточности, например, если округлить число 2.675 до второго знака, получится число 2.67 вместо 2.68. Это происходит из-за невозможности точно представить десятичные числа типа «float» в двоичном коде.

В Python 3

В третьей версии Python используется банковское округление. Это значит, что округление происходит до самого близкого чётного.

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

Примеры:

round(3.5) # = 4
round(9.5) # = 10
round(6.5) # = 6
round(-6.5) # = -6
round(-7.5) # = -8

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

Округление до сотых

У функции raund() есть ещё один аргумент. Он показывает до какого количества знаков после запятой следует округлять. Таким образом, если нам надо в Python округлить до сотых, этому параметру следует задать значение 2.

Пример округления до нужного знака:

round(3.555, 2) # = 3.56
round(9.515,1) # = 9.5
round(6.657,2) # = 6.66

Ошибки округления и модуль decimal

При округлении функцией round(), можно получить следующее:

round(2.65, 1) # = 2.6
round(2.85, 1) # = 2.9

Почему в одном случае округляется вниз, а в другом вверх? При переводе 2.85 в двоичную систему получается число, которое немного больше. Поэтому функция видит не «5», а «>5» и округляет вверх.

Проблему неточного представления чисел отлично иллюстрирует пример:

print (0.1 + 0.1 + 0.1)

0.30000000000000004

Из-за подобных ошибок числа типа «float» нельзя использовать там, где изменения значения на одну тысячную может привести к неверному результату. Решить данную проблему поможет модуль decimal.

decimal — модуль, позволяющий округлять десятичные дроби с почти 100% точностью. Его основной принцип: компьютер должен считать так, как считает человек. Речь идёт не о скорости вычисления, а о точности и отсутствии проблем неправильного представления чисел.