Ответ 1
Проблема, с которой вы связаны между -0.
и +0.
, является частью спецификации того, как должны работать поплавки (IEEE754). В некоторых случаях это нужно. См., Например, документы, которые связаны с документами для around
.
Также стоит отметить, что два нуля должны сравниваться с равными, поэтому
np.array(-0.)==np.array(+0.)
# True
То есть, я думаю, проблема более вероятна с вашим сопоставлением уникальности. Например:
a = np.array([-1., -0., 0., 1.])
np.unique(a)
# array([-1., -0., 1.])
Если вы хотите сохранить числа в виде с плавающей запятой, но все нули одинаковы, вы можете использовать:
x = np.linspace(-2, 2, 6)
# array([-2. , -1.2, -0.4, 0.4, 1.2, 2. ])
y = x.round()
# array([-2., -1., -0., 0., 1., 2.])
y[y==0.] = 0.
# array([-2., -1., 0., 0., 1., 2.])
# or
y += 0.
# array([-2., -1., 0., 0., 1., 2.])
Обратите внимание, что вам нужно выполнить эту дополнительную работу, так как вы пытаетесь избежать спецификации с плавающей точкой.
Обратите также внимание, что это связано не с ошибкой округления. Например,
np.fix(np.array(-.4)).tostring().encode('hex')
# '0000000000000080'
np.fix(np.array(-0.)).tostring().encode('hex')
# '0000000000000080'
То есть результирующие числа будут точно такими же, но
np.fix(np.array(0.)).tostring().encode('hex')
# '0000000000000000'
отличается. Вот почему ваш метод не работает, поскольку он сравнивает двоичное представление чисел, которое отличается для двух нулей. Поэтому я считаю, что проблема скорее является методом сравнения, чем общей идеей сравнения чисел с плавающей запятой для уникальности.
Быстрый тест времени для различных подходов:
data0 = np.fix(4*np.random.rand(1000000,)-2)
# [ 1. -0. 1. -0. -0. 1. 1. 0. -0. -0. .... ]
N = 100
data = np.array(data0)
print timeit.timeit("data += 0.", setup="from __main__ import np, data", number=N)
# 0.171831846237
data = np.array(data0)
print timeit.timeit("data[data==0.] = 0.", setup="from __main__ import np, data", number=N)
# 0.83500289917
data = np.array(data0)
print timeit.timeit("data.astype(np.int).astype(np.float)", setup="from __main__ import np, data", number=N)
# 0.843791007996
Я согласен с точкой @senderle в том, что если вы хотите простые и точные сравнения и можете обойтись с помощью int, ints будет проще. Но если вам нужны уникальные поплавки, вы тоже сможете это сделать, хотя вам нужно сделать это немного осторожнее. Основная проблема с поплавками заключается в том, что у вас могут быть небольшие различия, которые могут быть введены из вычислений и не отображаются в обычном print
, но это не огромный барьер, и особенно не после round, fix, rint
для разумного диапазона поплавков.