Подтвердить что ты не робот

Диапазон с шагом типа float

В документации в основном говорится, что range должен вести себя точно так же, как и эта реализация (для положительного step):

def range(start, stop, step):
  x = start
  while True:
    if x >= stop: return
    yield x
    x += step

В нем также говорится, что его аргументы должны быть целыми числами. Почему это? Разве это определение не является вполне допустимым, если шаг - это float?

В моем случае, я предпочитаю. нуждающаяся в функции range, которая принимает тип float как аргумент step. Есть ли в Python или мне нужно реализовать свои собственные?


Более конкретно: как бы я перевел этот код C прямо на Python красивым способом (т.е. не просто выполнить его с помощью while -loop вручную):

for(float x = 0; x < 10; x += 0.5f) { /* ... */ }
4b9b3361

Ответ 1

Вы можете использовать numpy.arange.

EDIT: документы предпочитают numpy.linspace. Спасибо @Droogans для заметок =)

Ответ 2

Одним из объяснений может быть проблема округления с плавающей запятой. Например, если вы могли бы позвонить

range(0, 0.4, 0.1)

вы можете ожидать вывод

[0, 0.1, 0.2, 0.3]

но вы действительно получите что-то вроде

[0, 0.1, 0.2000000001, 0.3000000001]

из-за проблем округления. А поскольку диапазон часто используется для генерации индексов какого-то типа, это целые числа.

Тем не менее, если вы хотите генератор диапазона для поплавков, вы можете просто свернуть свой.

def xfrange(start, stop, step):
    i = 0
    while start + i * step < stop:
        yield start + i * step
        i += 1

Ответ 3

Чтобы иметь возможность использовать десятичные числа в выражении диапазона, классный способ для этого состоит в следующем: [x * 0,1 для x в диапазоне (0, 10)]

Ответ 4

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

То, что вы действительно хотите, - это арифметическая прогрессия; следующий код будет работать довольно успешно для int, float и complex... и строк и списков...

def arithmetic_progression(start, step, length):
    for i in xrange(length):
        yield start + i * step

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

>>> 10000 * 0.0001, sum(0.0001 for i in xrange(10000))
(1.0, 0.9999999999999062)
>>> 10000 * (1/3.), sum(1/3. for i in xrange(10000))
(3333.333333333333, 3333.3333333337314)

Исправление: здесь конкурентный общий гаджет:

def kahan_range(start, stop, step):
    assert step > 0.0
    total = start
    compo = 0.0
    while total < stop:
        yield total
        y = step - compo
        temp = total + y
        compo = (temp - total) - y
        total = temp

>>> list(kahan_range(0, 1, 0.0001))[-1]
0.9999
>>> list(kahan_range(0, 3333.3334, 1/3.))[-1]
3333.333333333333
>>>

Ответ 5

Когда вы добавляете числа с плавающей точкой вместе, часто возникает небольшая ошибка. Вернул бы range(0.0, 2.2, 1.1) [0.0, 1.1] или [0.0, 1.1, 2.199999999]? Нет никакого способа быть уверенным без тщательного анализа.

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

Ответ 6

Вот специальный случай, который может быть достаточно хорошим:

 [ (1.0/divStep)*x for x in range(start*divStep, stop*divStep)]

В вашем случае это будет:

#for(float x = 0; x < 10; x += 0.5f) { /* ... */ } ==>
start = 0
stop  = 10
divstep = 1/.5 = 2 #This needs to be int, thats why I said 'special case'

и так:

>>> [ .5*x for x in range(0*2, 10*2)]
[0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5]

Ответ 7

Это то, что я буду использовать:

numbers = [float(x)/10 for x in range(10)]

а не:

numbers = [x*0.1 for x in range(10)]
that would return :
[0.0, 0.1, 0.2, 0.30000000000000004, 0.4, 0.5, 0.6000000000000001, 0.7000000000000001, 0.8, 0.9]

надеюсь, что это поможет.

Ответ 8

Вероятно, потому что вы не можете иметь часть итерации. Кроме того, floats являются неточными.