Is there a Python construct to allow me to do something like
this:
for i in range(-10.5, 10.5, 0.1):
...
If there is such a thing already available, I'd like
to use it, otherwise I can write a function to mimic this,
but I thought I'd check (my search yielded nothing).
Thanks,
Esmail
Write a function
--
Aahz (aa...@pythoncraft.com) <*> http://www.pythoncraft.com/
"Typing is cheap. Thinking is expensive." --Roy Smith
In this particular example, you could do this:
for i in range(-105, 105):
i = 0.1*i
...
In general, you'd have to write your own (generator) function.
--
Arnaud
I'd recommend using integer arithmetic:
for ten_times_i in range(-105, 106):
i = ten_times_i / 10.0
...
This has the advantage that it's clear that
you want to include the endpoint 10.5. (*Did*
you want to include the endpoint?)
Presumably you'd want the float version
to be interpreted as:
i = -10.5
while i < 10.5:
...
i += 0.1
(which isn't *quite* right, because the
value of i that you end up with *after* the
while loop has run to completion is 0.1
more than the last value used within the
loop).
The big problem with this is that 0.1
is not exactly representable as a float, and
so the successive additions in the
assignment i += 0.1 are subject to
(small) rounding errors. As a result, it's
not clear whether the value of i for the last
loop is going to be 10.4+small_error or
10.5-small_error.
Mark
Cheers,
Esmail
Sometimes I use an improved version of this:
http://code.activestate.com/recipes/66472/
Bye,
bearophile
neat .. lots of code to study there. Thanks,
Esmail
> Hello all,
>
> Is there a Python construct to allow me to do something like
> this:
>
> for i in range(-10.5, 10.5, 0.1):
> ...
Note that those values are of type ‘float’, which is a distinct type
from ‘Decimal’ with very different behaviour.
> If there is such a thing already available, I'd like to use it,
> otherwise I can write a function to mimic this, but I thought I'd
> check (my search yielded nothing).
You can write a function to do it.
Alternatively, this case seems simple enough that you can write a
generator expression. Assuming you want ‘Decimal’ values:
>>> from decimal import Decimal
>>> amounts = (Decimal(mantissa)/10 for mantissa in range(-105, 105))
>>> for amount in amounts:
... print amount
...
-10.5
-10.4
-10.3
-10.2
-10.1
-10
-9.9
…
9.6
9.7
9.8
9.9
10
10.1
10.2
10.3
10.4
--
\ “I have a large seashell collection, which I keep scattered on |
`\ the beaches all over the world. Maybe you've seen it.” —Steven |
_o__) Wright |
Ben Finney
Another nice solution stored away for use!
Thanks,
Esmail
Care to contribute your improvements back to the recipe? Or at least
here? I for one am curious to see how you do it.
--
Steven
for i in range(-105, 105):
i = i / 10.0
# do stuff here using i
To match the semantics of range(), the final value to ctr must be less
than but not equal to 10.5.
>>> print ctr
10.6
Your solution does not do this -- it goes one steps too many, and then
misleadingly fails to print the value. This is a bug waiting to hit, any
time somebody runs your loop then goes to use ctr outside the loop.
--
Steven
Isn't so easy. You have representation errors and rounding errors here,
and they accumulate. The last number printed should be 10.4 but I get 10.5:
...
10.3
10.4
10.5
(or more precisely, 10.499999999999959)
Also, after exiting a for loop, the *last* value used is retained. In your
while loop, the ctr variable contains the *next* value.
--
Gabriel Genellina
All this discussion makes me wonder if it would be a good idea
for Python to have this feature (batteries included and all) - it
would have its uses, no?
> All this discussion makes me wonder if it would be a good idea
> for Python to have this feature (batteries included and all) - it
> would have its uses, no?
What feature are you referring to? Python already has fixed-point
decimal values in the ‘decimal.Decimal’ type, if that's what you mean.
--
\ “I spent all my money on a FAX machine. Now I can only FAX |
`\ collect.” —Steven Wright |
_o__) |
Ben Finney
Well, sometimes more discussion == less consensus :)
But it's really easy to roll your own:
from decimal import Decimal
def args2dec(fn):
'''*args to Decimal decorator'''
float2dec = lambda f: Decimal(str(f))
def _args2dec(*args):
args = map(float2dec, args)
return fn(*args)
return _args2dec
@args2dec
def drange(start, stop, step):
while start < stop:
yield start
start += step
And remarkably quickly at that:
>>> ctr = -10.5
>>> for i in range(-105, 106):
... i *= 0.1
... if i != ctr: print repr(i), repr(ctr)
... ctr += 0.1
...
-10.0 -10.000000000000002
etc.
--
\S
under construction
I'd prefer not to force my users into using the Decimal type. Maybe
float fits their needs better. So here's a generalized xrange
replacement, which fixes an error in the drange implementation above
(try it with a negative step). It's also highly *not* optimized.
Calculating i * step every time slows it down. Speeding it back up is
an exercise for the reader.
def general_xrange(start, stop, step=1):
target = stop * step
if start * step > target:
raise ValueError
i = start
while i * step < target:
yield i
i += step
Cheers,
Cliff