Ошибки округления с плавающей запятой в Python с использованием Numpy

У меня проблема, которая, как мне кажется, связана с работой с поплавками и точностью, но я не очень хорошо разбираюсь в различных тонкостях. Я математик, и в моем уме я мог бы все еще просто работать с десятичными знаками на доске. Я начну изучать этот вопрос, а пока мне интересно, существуют ли какие-либо общие методы работы с числами с плавающей запятой, которые могли бы решить проблему, о которой я расскажу ниже.

У меня есть массив десятичных знаков, который я хотел бы округлить до ближайшего 0,02. Первоначально я сделал это, разделив каждый элемент массива на 0,02, округлив результат, а затем снова умножив на 0,02. Фактические данные генерируются некоторым кодом, обрабатывающим ввод, но это демонстрирует проблему:

x = np.array([.45632, .69722, .40692])
xx = np.round(x/.02)*.02

Вроде всё правильно округляет, как могу проверить:

xx
array([0.46, 0.7, 0.4])

Однако, если я проверю первый и второй элемент, я получаю:

xx[0]
0.46000000000000002
xx[1]
0.70000000000000007

Каждый элемент массива имеет тип numpy.float64. Проблема возникает позже, потому что я использую эти числа с операторами сравнения для выбора подмножеств данных, и то, что происходит потом, немного непредсказуемо:

xx[0] == .46
True

Но,

xx[1] == .70
False

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


person user3749714    schedule 26.08.2014    source источник
comment
Вероятно, вам следует сравнивать поплавки без оператора ==. Вместо этого сравните число с диапазоном значений, например, xx[0] находится в пределах 1e-10 от 0,46?. Или просто не используйте числа с плавающей запятой (сохраняйте каждое число в 100 раз больше, чем оно есть на самом деле).   -  person irrelephant    schedule 26.08.2014
comment
взгляните на isclose или allclose в (numpy)[docs.scipy.org/doc/numpy-dev/reference/generated/.   -  person Marcin    schedule 26.08.2014
comment
Обязательная ссылка: floating-point-gui.de   -  person Warren Weckesser    schedule 26.08.2014


Ответы (2)


Вместо использования == для выбора подмножества данных попробуйте использовать numpy .isclose(). Это позволяет указать относительный/абсолютный допуск для сравнения (absolute(a - b) <= (atol + rtol * absolute(b)))

person Joel Vroom    schedule 26.08.2014
comment
На самом деле я собирался ответить на свой вопрос и предложить приемлемую разницу и оператор ‹, но это полезная маленькая функция, о которой нужно знать. - person user3749714; 27.08.2014
comment
ссылка не работает (невозможно изменить): docs.scipy. org/doc/numpy/reference/generated/numpy.isclose.html - person K.S.; 04.01.2020

Для этого также можно использовать Python format.

print format(xx[1], '.100f')

этот код возвращает фактическое значение xx[1]

ie. xx[1] = 0.70000000000000006661338147750939242541790008544921875

Вы можете проверить это по коду, показанному ниже

if xx[1] == 0.70000000000000006661338147750939242541790008544921875:
    print 'true'
person Aslam Khan    schedule 26.08.2014