Тип чисел с плавающей точкой: подробное руководство

Раздел: Основы Python -> Типы и структуры данных

Числа с плавающей точкой (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

Тип float в Python - comments

En
Float python (python)