#python #numpy
#python #numpy
Вопрос:
a = 1.25
if a in np.arange(1,2,0.05):
print(a)
но это условие if не выполняется, хотя
print(np.arange(1,2,0.05))
[ 1. 1.05 1.1 1.15 1.2 1.25 1.3 1.35 1.4 1.45 1.5 1.55 1.6 1.65 1.7 1.75 1.8 1.85 1.9 1.95]
в нем есть 1.25.
Я читал, что arange на самом деле не является последовательным, но есть ли какой-либо обходной путь для этого?
Ответ №1:
Это потому 1.25
, что в этом диапазоне его на самом деле нет 1.2500000000000002
, и это потому, что numpy по умолчанию использует значение с плавающей запятой двойной точности для чисел с плавающей запятой, а в случаях, когда десятичные дроби не могут быть представлены точно как двоичные дроби, они могут содержать более точное значение для чисел с плавающей запятой. И то, что вы видите в результате печати, является просто форматированным представлением реального значения.
In [58]: l = np.arange(1,2,0.05)
In [59]: l[5]
Out[59]: 1.2500000000000002
In [60]: type(l[5])
Out[60]: numpy.float64
Одним из способов решения этой проблемы является приведение типа к float32
:
In [61]: l = np.arange(1,2,0.05).astype(np.float32)
In [62]: a = 1.25
In [63]: type(a)
Out[63]: float
In [64]: a in l
Out[64]: True
Комментарии:
1. «десятичные дроби не могут быть представлены точно как двоичные дроби» — это в равной степени верно для литерала
1.25
, с которым сравниваются значения в массиве (который также будет 64-битным с плавающей точкой). Я думаю, проблема в том, что размер шага не может быть представлен точно как двоичная дробь. Например,1.25 in np.arange(1, 2, 2**-4) == True
.2. @ali_m Да, спасибо за разъяснение, но, как я уже сказал, это
decimal fractions
, и это происходит после добавления шага, и причиной может быть шаг или результат.
Ответ №2:
Используется item
для печати значений в полном великолепии:
In [83]: for i in np.arange(1,2,0.05):print(i.item())
1.0
1.05
1.1
1.1500000000000001
1.2000000000000002
1.2500000000000002
1.3000000000000003
1.3500000000000003
1.4000000000000004
1.4500000000000004
1.5000000000000004
1.5500000000000005
1.6000000000000005
1.6500000000000006
1.7000000000000006
1.7500000000000007
1.8000000000000007
1.8500000000000008
1.9000000000000008
1.9500000000000008
Даже linspace
эти дополнительные цифры отключены в конце:
In [84]: for i in np.linspace(1,2,21):print(i.item())
1.0
1.05
1.1
1.15
1.2
1.25
1.3
1.35
1.4
1.45
1.5
1.55
1.6
1.65
1.7000000000000002
1.75
1.8
1.85
1.9
1.9500000000000002
2.0
in
и ==
тесты не являются хорошей идеей при работе с поплавками.
isclose
и allclose
проверка на небольшие различия, а не на точное совпадение
In [89]: np.isclose(np.arange(1,2,0.05),1.25)
Out[89]:
array([False, False, False, False, False, True, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False], dtype=bool)
In [90]: np.isclose(np.arange(1,2,0.05),1.25).any()
Out[90]: True
Посмотрите на isclose
код, чтобы увидеть все, что связано с сравнением чисел с плавающей точкой.