Что такое параметр разрешения numpy float

Я ищу больше понимания о параметре «разрешение» numpy float (я думаю, любой компьютер, определенный float в этом отношении).

Рассмотрим следующий скрипт:

import numpy as np
a = np.finfo(10.1)
print a

Я получаю вывод, который, среди прочего, распечатывает:

precision=15   resolution= 1.0000000000000001e-15
max= 1.797(...)e+308
min= -max

В документации numpy указывается: «разрешение: (число с плавающей запятой соответствующего типа) Приблизительное десятичное разрешение этого типа, т. Е. 10 ** - точность». источник

разрешение выводится из точности, но, к сожалению, это определение несколько круглое: «точность (целое число): приблизительное количество десятичных цифр, до которых этот тип числа с плавающей запятой точен». источник

Я понимаю, что числа с плавающей запятой являются просто конечными представлениями действительных чисел и, следовательно, имеют ошибку в их представлении, и что точность, вероятно, является мерой этого отклонения. Но означает ли это на практике, что я должен ожидать ошибочных результатов, если я выполняю операции, используя числа, меньшие разрешения? Как я могу количественно определить ошибку, скажем, сложения двух чисел с плавающей запятой, учитывая их точность? Если разрешение такое «большое», как 1e-15, почему наименьшее допустимое число должно быть порядка 1e-308?

Заранее спасибо!


person Sergiy    schedule 08.09.2015    source источник


Ответы (1)


Короткий ответ: "не путайте numpy.finfo с numpy.spacing".

finfo работает с dtype, а spacing работает со значением.

Исходная информация

Но сначала несколько общих пояснений:


Ключевая часть, которую нужно понять, заключается в том, что числа с плавающей запятой аналогичны экспоненциальной записи. Точно так же, как вы написали бы 0,000001 как 1.0 x 10^-6, числа с плавающей запятой похожи на c x 2^q. Другими словами, они состоят из двух отдельных частей — коэффициента (c, также известного как «значащая») и показателя степени (q). Эти два значения хранятся как целые числа.

Следовательно, то, насколько близко может быть представлено значение (давайте будем думать об этом как о степени дискретизации), является функцией обеих частей и зависит от величины значения.

Однако «точность» (как указано в np.finfo) по сути является количеством значащих цифр, если число было записано в экспоненциальной записи с основанием 10. «Разрешение» — это разрешение коэффициента (часть впереди), если значение было записано в той же научной нотации с основанием 10 (т. е. 10^-precision). Другими словами, оба являются только функцией коэффициента.

специфический для Numpy

Для numpy.finfo "точность" и "разрешение" просто противоположны друг другу. Ни один из них не говорит вам, насколько близко представлено конкретное число. Это чисто функция dtype.

Вместо этого, если вас беспокоит абсолютная степень дискретизации, используйте numpy.spacing(your_float). Это вернет разницу в следующем наибольшем значении в этом конкретном формате (например, для float32 оно отличается от float64).

Примеры

Например:

In [1]: import numpy as np

In [2]: np.spacing(10.1)
Out[2]: 1.7763568394002505e-15

In [3]: np.spacing(10000000000.1)
Out[3]: 1.9073486328125e-06

In [4]: np.spacing(1000000000000.1)
Out[4]: 0.0001220703125

In [5]: np.spacing(100000000000000.1)
Out[5]: 0.015625

In [6]: np.spacing(10000000000000000.1)
Out[6]: 2.0

Но точность и разрешение не меняются:

In [7]: np.finfo(10.1).precision
Out[7]: 15

In [8]: np.finfo(10000000000000000.1).precision
Out[8]: 15

In [9]: np.finfo(10.1).resolution
Out[9]: 1.0000000000000001e-15

In [10]: np.finfo(10000000000000000000.1).resolution
Out[10]: 1.0000000000000001e-15

Также обратите внимание, что все это зависит от типа данных, который вы используете:

In [11]: np.spacing(np.float32(10.1))
Out[11]: 9.5367432e-07

In [12]: np.spacing(np.float32(10000000000000.1))
Out[12]: 1048576.0

In [13]: np.finfo(np.float32).precision
Out[13]: 6

In [14]: np.finfo(np.float32).resolution
Out[14]: 1e-06

In [15]: np.spacing(np.float128(10.1))
Out[15]: 8.6736173798840354721e-19

In [16]: np.spacing(np.float128(10000000000000.1))
Out[16]: 9.5367431640625e-07

In [17]: np.finfo(np.float128).precision
Out[17]: 18

In [18]: np.finfo(np.float128).resolution
Out[18]: 1.0000000000000000007e-18

Конкретные вопросы

Теперь по вашим конкретным вопросам:

Но означает ли это на практике, что я должен ожидать ошибочных результатов, если я выполняю операции, используя числа, меньшие разрешения?

Нет, потому что точность/разрешение (в терминах numpy.finfo) является только функцией коэффициента и не учитывает показатель степени. Очень маленькие и очень большие числа имеют одинаковую «точность», но это не абсолютная «ошибка».

Как правило, при использовании терминов «разрешение» или «точность» из finfo думайте об экспоненциальном представлении. Если мы работаем с небольшими числами с одинаковыми величинами, нам не о чем беспокоиться.

Давайте возьмем десятичный математический случай с 6 значащими цифрами (что-то вроде float32):

1.20000 x 10^-19 + 2.50000 x 10^-20 => 1.45000 x 10^19

Однако, если мы оперируем числами с совершенно разными величинами, но ограниченной точностью (опять же, 6 значащих цифр):

1.20000 x 10^6 + 2.50000 x 10^-5 => 1.20000

Мы начнем видеть эффекты довольно ясно.

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

Используйте np.spacing(result).

Если разрешение такое «большое», как 1e-15, почему наименьшее допустимое число должно быть порядка 1e-308?

Опять же, «разрешение» в этом случае не учитывает показатель степени, а только часть впереди.


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

person Joe Kington    schedule 08.09.2015
comment
Вау, потрясающий и подробный ответ! Большое спасибо! - person Sergiy; 10.09.2015