Числа с плавающей запятой в Python: типы данных и практические примеры
Числа с плавающей запятой в Python: основные принципы и нюансы
Числа с плавающей запятой (float) - один из базовых типов данных в Python, предназначенный для представления вещественных чисел. Они реализованы на основе стандарта IEEE 754 и обладают ограниченной точностью, что может приводить к неожиданным ошибкам при вычислениях. В этой статье разбираются основные способы работы с float и альтернативные подходы для ситуаций, требующих повышенной точности.
Основной способ: создание и арифметика с float
Как создать число с плавающей запятой и выполнить базовые операции?
Самый простой способ - записать число с десятичной точкой или использовать функцию float().
a = 3.14
b = float("2.718")
c = 1e-3 # научная нотация
print(a, b, c)
# Результат: 3.14 2.718 0.001Set str python (множество из строки в python)
Арифметические операции работают как обычно:
x = 0.1 + 0.2
print(x) # Результат: 0.30000000000000004Python переменная время (переменные для времени в python)
Проблема:
Из-за двоичного представления числа 0.1 и 0.2 не могут быть точно сохранены, поэтому результат сложения содержит погрешность. Это типичная ошибка при сравнении: 0.1 + 0.2 == 0.3 вернёт False.
Решение: использовать округление, сравнение с допуском или более точный тип Decimal.
Для приведения целых чисел к float используется float():
n = 5
print(float(n)) # 5.0Python объект тип (тип объекта в python)
Обратное преобразование int() отбрасывает дробную часть (не округляет):
print(int(3.9)) # 3
print(int(-3.9)) # -3вещественные значения python (вещественные значения в python)
Вариант 1: Decimal - точные десятичные вычисления
Как выполнять точные финансовые расчёты без погрешностей двоичной арифметики?
Модуль decimal предоставляет десятичный тип с настраиваемой точностью. Идеален для денежных операций и ситуаций, где важна десятичная точность.
from decimal import Decimal, getcontext
getcontext().prec = 28 # точность по умолчанию
d1 = Decimal('0.1')
d2 = Decimal('0.2')
print(d1 + d2) # 0.3вывести тип данных python (вывод типа данных в python)
Проблемы:
- Производительность ниже, чем у float.
- Необходимо передавать числа строками или целыми, чтобы избежать неявного преобразования float.
Можно задать округление:
from decimal import ROUND_HALF_UP
price = Decimal('19.995').quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)
print(price) # 20.00Python двоичные данные (работа с двоичными данными в python)
Вариант 2: Fraction - рациональные числа
Как представлять числа в виде дробей, чтобы избежать ошибок округления при делении?
Модуль fractions позволяет работать с рациональными числами точно.
from fractions import Fraction
f1 = Fraction(1, 3)
f2 = Fraction(2, 5)
print(f1 + f2) # 11/15
print(float(f1)) # 0.3333333333333333 (при преобразовании появляется погрешность)переменная int python какая переменная (переменная int в python - что это?)
Проблема:
При преобразовании Fraction обратно в float точность теряется. Использовать Fraction следует, если все расчёты остаются рациональными.
Вариант 3: Округление чисел
Как округлить float до заданного числа знаков после запятой?
Функция round(), форматирование строк и методы math.floor/math.ceil.
x = 2.675
print(round(x, 2)) # 2.67 (банковское округление: к чётному)
# Форматирование
print(f"{x:.2f}") # 2.67
print("{:.2f}".format(x)) # 2.67
# Математические функции
import math
print(math.floor(2.7)) # 2
print(math.ceil(2.1)) # 3логические значения python (логические значения в python)
Типичная ошибка:
round() может давать неожиданные результаты из-за двоичного представления: round(2.675, 2) даёт 2.67, а не 2.68. Для строгого правильного округления используйте Decimal с ROUND_HALF_UP.
Вариант 4: Сравнение чисел с допуском
Как корректно проверить равенство двух float?
Вместо == используется сравнение разности с маленьким epsilon.
a = 0.1 + 0.2
b = 0.3
e = 1e-9
print(abs(a - b) < e) # Trueдлина переменной python (длина числа и переменной в python)
Проблема:
Выбор epsilon - нетривиальная задача. Слишком маленький - возможен false negative, слишком большой - false positive. Лучше использовать math.isclose.
Вариант 5: math.isclose - стандартный способ сравнения
Как проверить, что два float приблизительно равны, с учётом масштаба чисел?
import math
print(math.isclose(0.1 + 0.2, 0.3)) # True, по умолчанию rel_tol=1e-9, abs_tol=0.0
print(math.isclose(1000000000.1, 1000000000.2, rel_tol=1e-10)) # False, потому что разница велика относительно масштабаопределение объекта python (определение типа объекта в python)
Можно задать абсолютный допуск:
print(math.isclose(0.000001, 0.000003, abs_tol=1e-5)) # TrueРасширенные примеры работы с числами с плавающей запятой
Пример 1: Проблема точности на практике
# Демонстрация накопления ошибки
s = 0.0
for i in range(10):
s += 0.1
print(s) # 0.9999999999999999
print(s == 1.0) # False0.9999999999999999 False
Пример 2: Использование Decimal для точного суммирования
from decimal import Decimal, getcontext
getcontext().prec = 30
s = Decimal('0.0')
for i in range(10):
s += Decimal('0.1')
print(s) # 1.0
print(s == Decimal('1.0')) # True1.0 True
Пример 3: Fraction для рациональных вычислений
from fractions import Fraction
# Вычисление суммы 1/3 + 1/6
f1 = Fraction(1, 3)
f2 = Fraction(1, 6)
print(f1 + f2) # 1/2
print(float(f1 + f2)) # 0.51/2 0.5
Пример 4: Форматирование с фиксированным числом знаков
value = 1234.56789
print(f"{value:12.3f}") # 1234.568
print(f"{value:012.3f}") # 0001234.568
print(f"{value:.2e}") # 1.23e+031234.568 0001234.568 1.23e+03
Пример 5: Округление с Decimal и разными режимами
from decimal import Decimal, ROUND_HALF_UP, ROUND_DOWN, ROUND_CEILING
d = Decimal('2.675')
print(d.quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)) # 2.68
print(d.quantize(Decimal('0.01'), rounding=ROUND_DOWN)) # 2.67
print(d.quantize(Decimal('0.01'), rounding=ROUND_CEILING)) # 2.68 (вверх)2.68 2.67 2.68
Пример 6: math.isclose с разными tolerances
import math
# Сравнение больших чисел с относительным допуском
x = 1e10
print(math.isclose(x, x + 1, rel_tol=1e-9)) # True (разница 1 на 1e10)
print(math.isclose(x, x + 1, rel_tol=1e-11)) # False
# Абсолютный допуск для малых чисел
y = 0.0001
z = 0.00011
print(math.isclose(y, z, abs_tol=1e-5)) # True
print(math.isclose(y, z, abs_tol=1e-6)) # FalseTrue False True False
Пример 7: Бесконечность и NaN
import math
inf = float('inf')
nan = float('nan')
print(inf * 2) # inf
print(inf - inf) # nan
print(math.isnan(nan)) # True
print(math.isfinite(inf)) # Falseinf nan True False
Пример 8: Преобразование float в двоичное представление (для понимания)
import struct
def float_to_bin(f):
return ''.join(f'{b:08b}' for b in struct.pack('!d', f))
print(float_to_bin(0.1))
# Частичная распечатка знака, экспоненты, мантиссы0011111110111001100110011001100110011001100110011001100110011010