Числа с плавающей точкой Python: float, double и точность вычислений

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

Основное решение: float в Python как аналог double

Как в Python работать с числами двойной точности (double)?

В языке Python нет отдельного типа double. Все числа с плавающей точкой имеют тип float, который соответствует 64-битному представлению IEEE 754 (двойная точность). Это означает, что любой литерал с десятичной точкой или операция, возвращающая дробное число, создаёт объект float - аналог double в C, Java или Fortran.

x = 3.14159
print(type(x))  # 

Float double python (тип double и float в python)

Проблема: в Python невозможно использовать 32-битный float (одинарная точность) стандартными средствами. Если требуется меньше точности или экономия памяти, приходится прибегать к сторонним библиотекам (например, numpy.float32). В большинстве задач двойная точность избыточна, но гарантирует высокую точность вычислений.

Как создать число с плавающей точкой и проверить его размер?

import sys
a = 1.0
print(sys.getsizeof(a))  # occupies 24 bytes (object overhead)
24

Объект float в Python занимает 24 байта из-за служебной информации, хотя сами данные (64 бита) - 8 байт. Это следует учитывать при работе с большими массивами.

Вариант 1: Явное указание числа с плавающей точкой через Decimal для финансовых расчётов

Как избежать погрешностей округления при работе с деньгами?

Тип float не подходит для денежных операций из-за ошибок представления. Модуль decimal позволяет задать точность и округление.

from decimal import Decimal, getcontext
getcontext().prec = 28  # задаём точность 28 знаков
price = Decimal('19.99')
tax = Decimal('0.07')
total = price * (1 + tax)
print(total)  # 21.3893 (точное значение)
21.3893

Ошибка: передача в Decimal числа float (например, Decimal(19.99)) приводит к потере точности, так как сначала создаётся неточный float. Всегда используйте строковый литерал.

Вариант 2: Принудительное использование 32-битного float через NumPy

Как сократить потребление памяти в научных расчётах, где достаточно одинарной точности?

Библиотека NumPy поддерживает типы float32 (одинарная) и float64 (двойная). По умолчанию массивы создаются с float64.

import numpy as np
a32 = np.float32(1.0)
a64 = np.float64(1.0)
print(a32.dtype, a64.dtype)  # float32 float64
float32 float64

Проблема: смешивание float32 и float64 в операциях может привести к автоматическому приведению к более широкому типу. Контролируйте типы явно.

Вариант 3: Дробные числа через fractions для точного представления рациональных чисел

Как избежать погрешностей при работе с дробями вида 1/3?

Модуль fractions хранит числа как пару (числитель, знаменатель). Результат всегда точен.

from fractions import Fraction
a = Fraction(1, 3)
b = Fraction(2, 5)
print(a + b)  # 11/15
11/15

Недостаток: операции с Fraction медленнее, чем с float. Не подходит для больших массивов.

Вариант 4: Использование math.fsum для точного суммирования

Как сложить много чисел с плавающей точкой и минимизировать ошибку?

Функция math.fsum использует алгоритм Шевчука для точного суммирования.

import math
nums = [0.1] * 10
print(sum(nums))       # 0.9999999999999999
print(math.fsum(nums))  # 1.0
0.9999999999999999
1.0

Важно: fsum работает только с последовательностями чисел. Для итераторов результат тот же.

Расширенные примеры работы с float и double в Python

Пример 1: Сравнение чисел с плавающей точкой с допуском

Из-за ошибок представления прямое равенство float не рекомендуется.

Пример
a = 0.1 + 0.2
b = 0.3
print(a == b)  # False
# Используем допуск (tolerance)
tolerance = 1e-10
print(abs(a - b) < tolerance)  # True
False
True

Пример 2: Экспоненциальная запись и преобразование строк

Пример
num = 1.23e-4
print(num)  # 0.000123
print(f"{num:.2e}")  # 1.23e-04
# Из строки
s = "2.5e3"
print(float(s))  # 2500.0
0.000123
1.23e-04
2500.0

Пример 3: Максимальное и минимальное значение float

Пример
import sys
print(sys.float_info.max)    # 1.7976931348623157e+308
print(sys.float_info.min)    # 2.2250738585072014e-308
print(sys.float_info.epsilon) # 2.220446049250313e-16 (машинный эпсилон)
1.7976931348623157e+308
2.2250738585072014e-308
2.220446049250313e-16

Пример 4: NaN и inf

Пример
import math
a = float('inf')
b = float('-inf')
c = float('nan')
print(math.isinf(a))  # True
print(math.isnan(c))  # True
# Операции с NaN
print(c + 1)  # nan
True
True
nan

Пример 5: Преобразование массива numpy из float64 в float32 и обратно

Пример
import numpy as np
arr = np.array([1.23456789, 2.34567891], dtype=np.float64)
arr32 = arr.astype(np.float32)
print(arr32)  # [1.2345679 2.3456788] (потеря точности)
# Обратно в float64 – потерянные знаки не восстанавливаются
arr_back = arr32.astype(np.float64)
print(arr_back)  # [1.2345678806304932, 2.3456788063049316]
[1.2345679 2.3456788]
[1.23456788 2.34567881]

Пример 6: Использование decimal.Decimal с контекстом для округления

Пример
from decimal import Decimal, ROUND_HALF_UP, getcontext
getcontext().prec = 4
getcontext().rounding = ROUND_HALF_UP
value = Decimal('2.675')
rounded = value.quantize(Decimal('0.01'))
print(rounded)  # 2.68 (а не 2.67, как было бы с float)
2.68

Пример 7: Получение битового представления float (через struct)

Пример
import struct
def float_to_bits(f):
    return bin(struct.unpack('!I', struct.pack('!f', f))[0])
# Для double (Python float)
def double_to_bits(d):
    return hex(struct.unpack('!Q', struct.pack('!d', d))[0])
print(float_to_bits(1.0))     # 0b0111111110000000000000000000000 (32 бита)
print(double_to_bits(1.0))    # 0x3ff0000000000000
0b111111110000000000000000000000
0x3ff0000000000000

тип double и float в Python - comments

En
Float double python (python)