Короткий ответ: "не путайте 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