Python numpy создает неожиданные результаты

Я использую функцию arange для определения итераций цикла for и получения неожиданных результатов.

i = arange(7.8,8.4,0.05)
print i

выдает следующее:

[ 7.8   7.85  7.9   7.95  8.    8.05  8.1   8.15  8.2   8.25  8.3   8.35 8.4 ]

но используя значение остановки 8.35 следующим образом

i = arange(7.8,8.35,0.05)

дает следующее

[ 7.8   7.85  7.9   7.95  8.    8.05  8.1   8.15  8.2   8.25  8.3 ]

Но я хочу, чтобы мой диапазон заканчивался на 8.35! Я знаю, что могу использовать значение остановки > 8.35 и < 8.4 для достижения моего результата, но почему это отличается и, на мой взгляд, непоследовательным?

Изменить: я использую версию 2.7

Ответы

Ответ 1

Возможно, это связано с ограничениями чисел с плавающей запятой. Из-за точности машины невозможно хранить все мыслимые значения как плавающие точки. Например:

>>> 8.4
8.4000000000000004
>>> 8.35
8.3499999999999996

Итак, 8.4 как плавающая точка немного больше фактического значения 8.4, в то время как 8.35 в качестве плавающей точки меньше, чем меньше.

Ответ 2

Я предполагаю, что вы видите эффекты округления с плавающей точкой.

numpy.arange делает то же самое, что и python range: он не включает "конечную точку". (например, range(0, 4, 2) будет давать [0,2] вместо [0,2,4])

Однако для шагов с плавающей точкой ошибки округления накапливаются, а иногда последнее значение фактически включает конечную точку.

Как указано в документации для arange:

При использовании нецелого шага, такого как 0,1, результаты часто будут быть последовательным. Для этих случаев лучше использовать linspace.

numpy.linspace генерирует определенное количество точек между начальной и конечной точками. Кстати, он по умолчанию включает конечные точки.

Ответ 3

помощь функции arange говорит

    For floating point arguments, the length of the result is
    ``ceil((stop - start)/step)``.  Because of floating point overflow,
    this rule may result in the last element of `out` being greater
    than `stop`.

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

в 2.7

>>> float(repr(2.3))
2.3

в 2.6

>>> float(repr(2.3))
2.2999999999999998

Ответ 4

У меня была та же проблема, и я применил свою собственную функцию для исправления этой проблемы округления с помощью numpy.arange:

import numpy as np
def my_arange(a, b, dr, decimals=6):
    res = [a]
    k = 1
    while res[-1] < b:
        tmp = round(a + k*dr,decimals)
        if tmp > b:
            break   
        res.append(tmp)
        k+=1

    return np.asarray(res)