Ответ 1
Вы можете использовать numpy.arange
.
EDIT: документы предпочитают numpy.linspace
. Спасибо @Droogans для заметок =)
В документации в основном говорится, что 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) { /* ... */ }
Вы можете использовать numpy.arange
.
EDIT: документы предпочитают numpy.linspace
. Спасибо @Droogans для заметок =)
Одним из объяснений может быть проблема округления с плавающей запятой. Например, если вы могли бы позвонить
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
Чтобы иметь возможность использовать десятичные числа в выражении диапазона, классный способ для этого состоит в следующем: [x * 0,1 для x в диапазоне (0, 10)]
Проблема с плавающей точкой заключается в том, что вы не можете получить такое же количество элементов, как вы ожидали, из-за неточности. Это может быть реальной проблемой, если вы играете с полиномами, где точное количество элементов очень важно.
То, что вы действительно хотите, - это арифметическая прогрессия; следующий код будет работать довольно успешно для 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
>>>
Когда вы добавляете числа с плавающей точкой вместе, часто возникает небольшая ошибка. Вернул бы range(0.0, 2.2, 1.1)
[0.0, 1.1]
или [0.0, 1.1, 2.199999999]
? Нет никакого способа быть уверенным без тщательного анализа.
Код, который вы опубликовали, является ОК, если вам это действительно нужно. Просто знайте о возможных недостатках.
Вот специальный случай, который может быть достаточно хорошим:
[ (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]
Это то, что я буду использовать:
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]
надеюсь, что это поможет.
Вероятно, потому что вы не можете иметь часть итерации. Кроме того, floats
являются неточными.