Тип чисел с плавающей точкой: подробное руководство
Числа с плавающей точкой (float) в Python представляют собой вещественные числа согласно стандарту IEEE 754 с двойной точностью (64 бита). Этот тип данных используется для работы с дробными числами, научными вычислениями и любыми задачами, где требуется высокая точность в широком диапазоне значений.
Основы работы с типом float
Наиболее эффективный подход при работе с float всегда помнить о погрешностях двоичного представления и использовать специальные инструменты для сравнения и округления. Например, для сравнения двух float чисел применяется math.isclose() или абсолютная разница с порогом eps. Для финансовых расчетов лучше использовать decimal.Decimal.
import math
x = 0.1 + 0.2
y = 0.3
# правильное сравнение
if math.isclose(x, y, rel_tol=1e-9):
print('Числа равны в пределах допуска')
Float python (тип float в python)
Числа равны в пределах допуска
Типичная ошибка:
Наивное сравнение x == y часто даёт False из-за погрешностей представления. Например, 0.1 + 0.2 == 0.3 возвращает False.
Как создать число с плавающей точкой из различных источников?
Для создания float Python автоматически интерпретирует числа с точкой как float. Также можно преобразовать строку, целое число или выполнить арифметическую операцию.
# Прямое задание
a = 3.14
b = -0.001
c = 1e10 # научная нотация
# Из строки
d = float('3.14')
e = float('inf')
f = float('nan')
# Из целого числа
g = float(42)
print(a, b, c, d, e, f, g)
3.14 -0.001 10000000000.0 3.14 inf nan 42.0
Возможные проблемы:
При преобразовании строк с неверным форматом (например, '3,14') возникнет исключение ValueError. Используется точка в качестве десятичного разделителя.
Как проверить, что float число является целым по значению?
Метод float.is_integer() возвращает True, если число представляет собой целое значение в пределах точности float (например, 5.0, 3.0).
print((5.0).is_integer()) # True
print((5.1).is_integer()) # False
print((-3.0).is_integer()) # True
print((1e100).is_integer()) # True (огромное число без дробной части)
True False True True
Примечание:
Этот метод не проверяет, можно ли число представить как int без потери точности. Например, 1e20 является целым, но его точное целое значение не помещается в 64 бита.
Как получить точное двоичное представление числа или его рациональное приближение?
Метод float.hex() возвращает строку шестнадцатеричного представления числа в формате IEEE 754. Метод float.as_integer_ratio() возвращает пару (числитель, знаменатель), представляющую число как рациональную дробь.
x = 0.1
print(x.hex())
print(x.as_integer_ratio())
0x1.999999999999ap-4 (3602879701896397, 36028797018963968)
Эти методы полезны для отладки и точного анализа погрешностей.
Особенности:
Знаменатель в as_integer_ratio() всегда является степенью двойки, поэтому не каждое десятичное число представляется точно.
Как округлить число с плавающей точкой до заданного количества знаков?
В Python есть несколько способов округления: встроенная функция round(), форматирование строк с format() или f-строки, и функция math.floor()/math.ceil() для округления вниз/вверх.
x = 3.141592653589793
print(round(x, 2)) # 3.14
print(round(x, 4)) # 3.1416
print(f'{x:.3f}') # 3.142
print(format(x, '.2f')) # 3.14
3.14 3.1416 3.142 3.14
Важно:
Функция round() использует банковское округление (round half to even), что может давать неожиданные результаты для чисел, заканчивающихся на 5. Например, round(2.5) возвращает 2, а round(3.5) возвращает 4.
Как сравнивать float числа с учётом погрешности?
Кроме math.isclose() можно использовать абсолютное сравнение с эпсилон или относительное сравнение. Метод math.isclose() позволяет задать относительный (rel_tol) и абсолютный (abs_tol) допуски.
import math
a = 1e-10
b = 1e-10 + 1e-15
print(math.isclose(a, b, rel_tol=1e-9, abs_tol=1e-12)) # True
c = 1e10
d = 1e10 + 0.1
print(math.isclose(c, d, rel_tol=1e-9)) # True (относительная разница мала)
True True
Частая ошибка:
Использование только абсолютного допуска для очень больших или очень маленьких чисел может быть некорректным. Рекомендуется комбинировать относительный и абсолютный допуски.
Как обрабатывать специальные значения inf и nan?
Бесконечность (inf) и не-число (nan) возникают при делении на ноль, выходе за диапазон и т.д. Для их проверки используются функции math.isinf() и math.isnan(). Сравнение через == с nan всегда даёт False, даже с самим собой.
import math
inf = float('inf')
nan = float('nan')
print(math.isinf(inf)) # True
print(math.isnan(nan)) # True
print(nan == nan) # False
print(inf > 1e308) # True
# Деление на ноль
x = 1e200 * 1e200
print(x) # inf
True True False True inf
Проблема:
Присутствие nan в вычислениях приводит к распространению неопределённости. Любая операция с nan возвращает nan. Поэтому перед арифметическими операциями стоит проверять на nan.
Расширенные примеры демонстрируют практическое применение описанных приёмов.
# Пример 1: накопление ошибки при многократном сложении
import math
total = 0.0
for i in range(10):
total += 0.1
print('Сумма десяти 0.1:', total)
print('Ожидаемое значение:', 1.0)
# Исправление с Decimal
from decimal import Decimal, getcontext
getcontext().prec = 28
total_d = Decimal('0')
for i in range(10):
total_d += Decimal('0.1')
print('Сумма с Decimal:', total_d)
Сумма десяти 0.1: 0.9999999999999999 Ожидаемое значение: 1.0 Сумма с Decimal: 1.0
# Пример 2: пользовательская функция почти равных
def almost_equal(a, b, rel_tol=1e-9, abs_tol=1e-12):
return abs(a-b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)
print(almost_equal(0.1+0.2, 0.3))
print(almost_equal(1e10, 1e10+0.1, rel_tol=1e-9))
True True
# Пример 3: различные способы форматирования float
x = 123.456789
print(f'{x:10.2f}')
print(f'{x:+10.2f}')
print(f'{x:010.2f}')
print(f'{x:.2e}')
print(f'{x:.2%}')
123.46
+123.46
0000123.46
1.23e+02
12345.68%
# Пример 4: работа с inf и nan в математических функциях
import math
print(math.isinf(float('inf')))
print(math.isnan(float('nan')))
print(float('nan') == float('nan'))
print(math.exp(1000))
print(math.log(0))
True True False inf -inf
# Пример 5: точное суммирование с math.fsum
values = [0.1]*10
print(sum(values))
print(math.fsum(values))
0.9999999999999999 1.0
# Пример 6: использование Fraction для точных рациональных
from fractions import Fraction
f1 = Fraction(1, 10)
f2 = Fraction(2, 10)
print(f1 + f2)
f3 = Fraction(0.3)
print(f3)
3/10 5404319552844595/18014398509481984