Плавающие числа Python: все о типе float
Тип float в Python: основы и варианты использования
Тип float в Python представляет числа с плавающей запятой двойной точности (64 бита) согласно стандарту IEEE 754. Он используется для хранения и обработки вещественных чисел, таких как 3.14, -0.001, 2.0e5. Основной способ создания - присваивание литерала с десятичной точкой или вызов функции float().
x = 3.14
y = float('2.718')
z = 1.5e-3
print(x, y, z)Type class python (класс type в python)
3.14 2.718 0.0015
Python string types (строковые типы в python)
При выполнении арифметических операций результат также является float. Однако из-за двоичного представления не все десятичные дроби могут быть представлены точно, что приводит к ошибкам округления.
Как преобразовать строку в число с плавающей запятой?
Функция float() принимает строку, содержащую десятичное число, и возвращает float. Поддерживаются научная нотация и знаки.
a = float('3.14')
b = float('-1.5e-2')
c = float('+2.0')
print(a, b, c)Python type str (тип str в python)
3.14 -0.015 2.0
Python object type (тип объекта в python)
Проблема: Если строка не является корректным представлением числа, возникает исключение ValueError. Например, float('abc') вызовет ошибку. Способ решения - обернуть вызов в try-except.
try:
value = float('не число')
except ValueError:
print('Ошибка преобразования')Python 3 types (типы данных в python 3)
Ошибка преобразования
Python float types (типы с плавающей запятой в python)
Как округлить float до заданного количества знаков после запятой?
Встроенная функция round() округляет число до указанного числа десятичных разрядов. Второй аргумент - количество знаков (может быть отрицательным для округления до десятков и т.д.).
x = 3.14159265
print(round(x, 2))
print(round(x, 4))
print(round(x, -1)) # до десятковPython int types (целочисленные типы в python)
3.14 3.1416 0.0
Типичная ошибка: round() использует банковское округление (round half to even), что может дать неожиданные результаты для чисел, оканчивающихся на 5. Например, round(2.5) даёт 2, а не 3. Для классического арифметического округления (вверх от 0.5) можно использовать модуль decimal с подходящим контекстом.
print(round(2.5))
print(round(3.5))
2 4
Как красиво отформатировать вывод float (например, задать фиксированное число знаков, выровнять)?
Используются f-строки с форматными спецификациями: f'{value:9.2f}' - общая ширина 9, 2 знака после запятой, выравнивание вправо. Также можно использовать format() или %-форматирование.
pi = 3.14159265
print(f'{pi:8.3f}')
print(f'{pi:.4e}')
print('{:>10.2f}'.format(pi))
3.142
3.1416e+00
3.14
Проблема: При форматировании с большим количеством знаков после запятой могут появиться лишние нули или неожиданные округления. Для финансовых расчётов лучше использовать Decimal, где можно точно контролировать точность.
Как безопасно сравнить два числа float на равенство, учитывая погрешность?
Прямое сравнение a == b часто ложно из-за ошибок округления. Модуль math предоставляет функцию isclose(), которая проверяет, находятся ли числа в пределах заданной относительной или абсолютной допустимой погрешности.
import math
a = 0.1 + 0.2
b = 0.3
print(a == b)
print(math.isclose(a, b, rel_tol=1e-9, abs_tol=0.0))
False True
Типичная ошибка: Использование round() для сравнения: round(a, 10) == round(b, 10). Это может работать, но не всегда корректно при различной величине чисел. Лучше применять math.isclose или Decimal.
Как получить точные десятичные вычисления (например, для финансов)?
Класс Decimal из модуля decimal позволяет работать с числами с плавающей запятой с десятичной точностью, избегая ошибок двоичного представления. Можно задать точность (количество знаков), округление и обрабатывать специальные значения.
from decimal import Decimal, getcontext
getcontext().prec = 6 # общая точность 6 знаков
a = Decimal('0.1')
b = Decimal('0.2')
c = a + b
print(c)
print(c == Decimal('0.3'))
0.3 True
Проблема: Decimal медленнее обычных float. Не стоит применять его для научных расчётов, где миллионы операций. Также требуется явное создание из строки, а не из float, иначе точность будет потеряна на этапе конвертации.
Как представить рациональное число точно (без потери точности)?
Модуль fractions содержит класс Fraction, который хранит числитель и знаменатель как целые числа, обеспечивая абсолютную точность для рациональных чисел. Поддерживается арифметика и преобразование в float.
from fractions import Fraction
a = Fraction(1, 3)
b = Fraction(2, 5)
c = a + b
print(c)
print(float(c))
11/15 0.7333333333333333
Недостаток: Размер числителя и знаменателя может расти, замедляя вычисления. Подходит только для рациональных чисел; иррациональные значения (например, sqrt(2)) не могут быть представлены точно.
Расширенные примеры работы с числами с плавающей запятой
Ниже приведены более сложные и нестандартные примеры использования float в Python.
Шестнадцатеричное представление float
x = 3.14
print(x.hex())
print(float.fromhex('0x1.91eb851eb851fp+1'))
0x1.91eb851eb851fp+1 3.14
Метод hex() возвращает строку, точно представляющую внутреннее двоичное значение. Обратное преобразование - float.fromhex().
Получение числителя и знаменателя (as_integer_ratio)
x = 0.125
print(x.as_integer_ratio())
(1, 8)
Метод возвращает кортеж (числитель, знаменатель), представляющий точное рациональное значение, лежащее в основе float. Для чисел, не представимых точно, знаменатель будет степенью двойки.
Бесконечность и NaN
import math
inf = float('inf')
nan = float('nan')
print(math.isinf(inf), math.isnan(nan))
print(inf + 1)
print(nan == nan) # всегда False
True True inf False
Бесконечность создаётся с помощью float('inf') (или '-inf'). NaN - 'nan'. Сравнение NaN с самим собой даёт False, поэтому для проверки используется math.isnan().
Ошибка точности при сложении 0.1 + 0.2
print(0.1 + 0.2)
print(repr(0.1 + 0.2))
print(f'{0.1 + 0.2:.55f}')
0.30000000000000004 0.30000000000000004 0.3000000000000000444089209850062616169452667236328125000000000
Это демонстрирует, что десятичная дробь 0.1 не может быть точно представлена в двоичной системе.
Использование Decimal с точностью 50 знаков
from decimal import Decimal, getcontext
getcontext().prec = 50
a = Decimal('1') / Decimal('3')
print(a)
print(a * 3)
0.33333333333333333333333333333333333333333333333333 1.0000000000000000000000000000000000000000000000000
Демонстрация высокой точности Decimal.
Сравнение с разными допусками
import math
x = 1e-10
y = 2e-10
print(math.isclose(x, y, rel_tol=0.5, abs_tol=1e-9))
print(math.isclose(x, y, rel_tol=1e-9, abs_tol=1e-9))
True False
В первом случае относительный допуск 50% (0.5) позволяет считать 1e-10 и 2e-10 близкими. Во втором - допуск 1e-9 недостаточен.
Битовое представление с помощью struct
import struct
x = 3.14
packed = struct.pack('d', x) # 'd' для double
print(' '.join(f'{b:08b}' for b in packed))
unpacked = struct.unpack('d', packed)[0]
print(unpacked)
01000000 00001001 00011110 10111000 01010001 11101011 10000101 00011111 3.14
Модуль struct позволяет упаковать float в байты и посмотреть его двоичное представление.
Векторные операции с numpy float
import numpy as np
arr = np.array([1.5, 2.3, 3.7], dtype=np.float64)
print(arr * 2)
print(arr.sum())
[3. 4.6 7.4] 7.5
NumPy использует аналогичный float64, но позволяет эффективно обрабатывать массивы.
Обработка ошибок при преобразовании
def safe_float(s):
try:
return float(s)
except ValueError:
return None
print(safe_float('123.45'))
print(safe_float('12a'))
123.45 None
Функция возвращает None при неудаче.