Машина Epsilon в Python

Пособие, которое я сейчас изучаю (я новичок), говорит:

"Числа, которые отличаются меньше, чем машинный эпсилон, численно одинаковы"

С помощью Python машинный epsilon для значений float можно получить, набрав

eps = numpy.finfo(float).eps

Теперь, если я проверяю

1 + eps/10 != 1

Я получаю False.

Но если я проверяю

0.1 + eps/10 != 0.1

Я получаю True.

Последнее логическое выражение оказывается ложным, если я делю eps на 100. Итак, как работает машина epsilon? Документация Python просто говорит

"Наименьшее представимое положительное число, такое, что 1.0 + eps!= 1.0. Тип eps - подходящий тип с плавающей точкой.

Спасибо заранее.

Ответ 1

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

Таким образом, epsilon относится к числу, к которому он добавлен, что фактически указано в документации, которую вы указали: "... такое, что 1.0 + eps!= 1.0". Если "ссылочный" номер меньше, например, один порядок магнита, то и eps также меньше.

Если бы это было не так, вы не могли бы рассчитать вообще с номерами, меньшими, чем eps (2.2e-16 в моем случае).

Ответ 2

В этом случае вы действительно не хотите np.finfo. То, что вам нужно, - это np.spacing, который вычисляет расстояние между входом и следующим наибольшим числом, которое может быть точно представлено.

По существу, np.spacing вычисляет "eps" для любого заданного числа. Он использует тип данных числа (собственные поплавки python - это 64-битные поплавки), поэтому np.float32 или np.float16 даст другой ответ, чем 64-битный float.

Например:

import numpy as np

print 'Float64, 1.0 -->', np.spacing(1.0)
print 'Float64, 1e12 -->', np.spacing(1e12)
print 'Float64, 1e-12 -->', np.spacing(1e-12)
print ''
print 'Float32, 1.0 -->', np.spacing(np.float32(1.0))
print 'Float32, 1e12 -->', np.spacing(np.float32(1e12))
print 'Float32, 1e-12 -->', np.spacing(np.float32(1e-12))

Что дает:

Float64, 1.0 --> 2.22044604925e-16
Float64, 1e12 --> 0.0001220703125
Float64, 1e-12 --> 2.01948391737e-28

Float32, 1.0 --> 1.19209e-07
Float32, 1e12 --> 65536.0
Float32, 1e-12 --> 1.0842e-19