Как выполнять сравнение чисел с плавающей запятой в Python

PythonBeginner
Практиковаться сейчас

Введение

Числа с плавающей запятой широко используются в Python для численных вычислений, но их представление иногда может привести к неожиданному поведению при сравнении значений. В этом руководстве вы узнаете основы представления чисел с плавающей запятой в Python и получите практические методы для точного сравнения таких чисел.

Представление чисел с плавающей запятой в Python

В Python числа с плавающей запятой представлены в соответствии со стандартом IEEE 754, который является широко принятым стандартом для представления вещественных чисел в компьютерах. Этот стандарт определяет формат и поведение арифметики с плавающей запятой, включая представление специальных значений, таких как положительная и отрицательная бесконечность, а также не-число (NaN).

Представление чисел с плавающей запятой

Числа с плавающей запятой в Python хранятся в 64-битном формате, также известном как "двойная точность" (double-precision). Этот формат состоит из трех компонентов:

  1. Знаковый бит: Определяет, является ли число положительным или отрицательным.
  2. Показатель степени: Представляет степень двойки, в которую возводится мантисса.
  3. Мантисса: Дробная часть числа.

Представление числа с плавающей запятой в Python можно визуализировать следующим образом:

graph TD A[Sign Bit] --> B[Exponent] B --> C[Significand]

Стандарт IEEE 754 определяет конкретные битовые шаблоны для представления специальных значений, таких как положительный и отрицательный ноль, положительная и отрицательная бесконечность, а также NaN.

Точность и округление

Арифметика с плавающей запятой в компьютерах не всегда точна из-за ограниченного количества бит, используемых для представления чисел. Это может привести к ошибкам округления и неожиданному поведению при сравнении значений с плавающей запятой. Например, следующий код демонстрирует эту проблему:

import sys

x = 0.1
y = 0.2
print(x + y)  ## Output: 0.30000000000000004

Причиной такого поведения является то, что двоичное представление 0.1 и 0.2 не может быть точно представлено в ограниченном количестве бит, используемых для хранения чисел с плавающей запятой.

Для решения этой проблемы в следующем разделе обсуждаются различные методы точного сравнения чисел с плавающей запятой.

Сравнение чисел с плавающей запятой

Сравнение чисел с плавающей запятой в Python может быть сложной задачей из-за несовершенства их представления. Для точного сравнения таких чисел можно использовать следующие методы:

Сравнение по абсолютной разности

Самый простой способ — проверить, меньше ли абсолютная разность между двумя числами с плавающей запятой некоторого малого порогового значения. Этот метод подходит, когда вы знаете ожидаемую точность сравниваемых значений.

import sys

x = 0.1
y = 0.2
epsilon = sys.float_info.epsilon  ## Наименьшее положительное число с плавающей запятой x такое, что 1.0 + x!= 1.0
if abs(x + y - 0.3) < epsilon:
    print("x + y is equal to 0.3")
else:
    print("x + y is not equal to 0.3")

Сравнение по относительной разности

В случаях, когда величина сравниваемых чисел может различаться, сравнение по относительной разности может быть более подходящим. Этот метод проверяет, является ли абсолютная разность между числами малой по сравнению с величиной самих чисел.

import sys

x = 1.0
y = 1.000000001
epsilon = sys.float_info.epsilon
if abs(x - y) / max(abs(x), abs(y)) < epsilon:
    print("x is equal to y")
else:
    print("x is not equal to y")

Сравнение по ULP (единице последнего разряда)

Метод сравнения по ULP проверяет, меньше ли разность между двумя числами с плавающей запятой определенного количества единиц последнего разряда (ULP). Этот подход более точен, чем методы сравнения по абсолютной или относительной разности.

import math

x = 0.1
y = 0.100000000000001
if abs(x - y) <= 2 * math.ulp(max(x, y)):
    print("x is equal to y")
else:
    print("x is not equal to y")

Применяя эти методы, вы сможете эффективно сравнивать числа с плавающей запятой в Python и учитывать несовершенства их представления.

Методы точного сравнения чисел с плавающей запятой

При работе с числами с плавающей запятой в Python важно использовать подходящие методы, чтобы обеспечить точное сравнение. Вот некоторые методы, которые вы можете применить:

Сравнение по абсолютной разности

При сравнении по абсолютной разности проверяется, меньше ли абсолютная разность между двумя числами с плавающей запятой некоторого малого порогового значения. Этот метод подходит, когда вы знаете ожидаемую точность сравниваемых значений.

import sys

x = 0.1
y = 0.2
epsilon = sys.float_info.epsilon  ## Наименьшее положительное число с плавающей запятой x такое, что 1.0 + x!= 1.0
if abs(x + y - 0.3) < epsilon:
    print("x + y is equal to 0.3")
else:
    print("x + y is not equal to 0.3")

Сравнение по относительной разности

При сравнении по относительной разности проверяется, является ли абсолютная разность между двумя числами с плавающей запятой малой по сравнению с величиной этих чисел. Этот метод полезен, когда величина сравниваемых чисел может различаться.

import sys

x = 1.0
y = 1.000000001
epsilon = sys.float_info.epsilon
if abs(x - y) / max(abs(x), abs(y)) < epsilon:
    print("x is equal to y")
else:
    print("x is not equal to y")

Сравнение по ULP (единице последнего разряда)

Метод сравнения по ULP проверяет, меньше ли разность между двумя числами с плавающей запятой определенного количества единиц последнего разряда (ULP). Этот подход более точен, чем методы сравнения по абсолютной или относительной разности.

import math

x = 0.1
y = 0.100000000000001
if abs(x - y) <= 2 * math.ulp(max(x, y)):
    print("x is equal to y")
else:
    print("x is not equal to y")

Применяя эти методы, вы сможете эффективно сравнивать числа с плавающей запятой в Python и обеспечить желаемый уровень точности в своих вычислениях.

Заключение

В этом Python-руководстве вы узнали о сложностях представления чисел с плавающей запятой и эффективных стратегиях для точного сравнения таких чисел. Понимая основные принципы и применяя рассмотренные методы, вы сможете писать более надежный и устойчивый Python-код, который корректно обрабатывает операции и сравнения с числами с плавающей запятой.