Проверка, находится ли конкретное значение с плавающей точкой в ​​списке / массиве в Python / numpy - PullRequest
3 голосов
/ 19 марта 2019

Необходимо соблюдать осторожность при проверке на равенство между числами с плавающей запятой, и обычно это следует делать с учетом допусков, используя, например, numpy.allcose .

Вопрос1: Безопасно ли проверять наличие определенного числа с плавающей запятой, используя ключевое слово "in" (или для этой цели существуют похожие ключевые слова / функции)?Пример:

if myFloatNumber in myListOfFloats:
  print('Found it!')
else:
  print('Sorry, no luck.')

Вопрос 2: Если нет, то каким было бы аккуратное и опрятное решение?

Ответы [ 2 ]

4 голосов
/ 19 марта 2019

Если вы не вычисляете свои числа с плавающей точкой в ​​одном и том же месте или с точно таким же уравнением, то у вас могут быть ложные отрицания с этим кодом (из-за ошибок округления). Например:

>>> 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 * 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
1 голос
/ 19 марта 2019

Q1: Зависит от того, как вы собираетесь это реализовать.Но, как уже упоминали другие с помощью float, не очень хорошая идея использовать оператор 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
...