Проверка, находится ли конкретное значение с плавающей точкой в списке / массиве в Python/numpy
Необходимо соблюдать осторожность при проверке на равенство между числами с плавающей запятой, и обычно это следует делать с учетом допусков, используя, например, numpy.allcose.
Вопрос 1: Безопасно ли проверять наличие определенного числа с плавающей запятой, используя ключевое слово "in" (или для этой цели существуют похожие ключевые слова / функции)? Пример:
if myFloatNumber in myListOfFloats:
print('Found it!')
else:
print('Sorry, no luck.')
Вопрос 2: Если нет, то каким было бы аккуратное и опрятное решение?
2 ответа
Если вы не вычисляете свои числа с плавающей точкой в одном и том же месте или с одним и тем же уравнением, то у вас могут быть ложные отрицания с этим кодом (из-за ошибок округления). Например:
>>> 0.1 + 0.2 in [0.6/2, 0.3] # We may want this to be True
False
В этом случае мы можем просто иметь кастом " in
"функция, которая на самом деле сделает это правдой (в этом случае может быть лучше / быстрее использовать numpy.isclose
вместо numpy.allclose
):
import numpy as np
def close_to_any(a, floats, **kwargs):
return np.any(np.isclose(a, floats, **kwargs))
В документации есть важное примечание:
Предупреждение по умолчанию
atol
не подходит для сравнения чисел, которые намного меньше единицы (см. Примечания). [...] если ожидаемые значения значительно меньше единицы, это может привести к ложным срабатываниям.
Примечание добавляет, что atol
не ноль вопреки math.isclose
"s abs_tol
, Если вам нужен пользовательский допуск при использовании close_to_any
, использовать kwargs
пройти rtol
и / или atol
вплоть до NumPy. В конце концов, ваш существующий код будет преобразован в это:
if close_to_any(myFloatNumber, myListOfFloats):
print('Found it!')
else:
print('Sorry, no luck.')
Или вы могли бы иметь несколько вариантов close_to_any(myFloatNumber, myListOfFloats, atol=1e-12)
, Обратите внимание, что 1e-12
является произвольным, и вы не должны использовать это значение, если у вас нет веских причин для этого.
Возвращаясь к ошибке округления, которую мы наблюдали в первом примере, это дало бы:
>>> close_to_any(0.1 + 0.2, [0.6/2, 0.3])
True
Q1: Зависит от того, как вы собираетесь это реализовать. Но, как другие упоминали с плавающими, это не такая хорошая идея для использования in
оператор.
Q2: Есть ли у вас какие-либо ограничения по производительности? Будет myListOfFloats
быть отсортированным?
Если это отсортированный список значений с плавающей запятой и если вам нужно сделать это как можно быстрее, вы можете реализовать алгоритм двоичного поиска.
Если данные не отсортированы, в зависимости от соотношения между количеством запросов, которые вы будете выполнять, и размером данных, вы можете отсортировать данные и сохранить их отсортированными.
Если у вас нет требований к производительности и скорости, вы можете использовать следующий пример в качестве основы:
def inrng(number1,number2,prec):
if(abs(number1-number2)<prec):
return True
else:
return False
precision=0.001
for i in myListOfFloats:
if(inrng(i,myInputNumber,precision)):
#do stuff