Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

for with decimal values?

1 view
Skip to first unread message

Esmail

unread,
May 2, 2009, 11:12:30 AM5/2/09
to pytho...@python.org
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):
...

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

Aahz

unread,
May 2, 2009, 11:17:27 AM5/2/09
to
In article <mailman.4975.1241277...@python.org>,

Write a function
--
Aahz (aa...@pythoncraft.com) <*> http://www.pythoncraft.com/

"Typing is cheap. Thinking is expensive." --Roy Smith

Arnaud Delobelle

unread,
May 2, 2009, 12:35:16 PM5/2/09
to
Esmail <ebo...@hotmail.com> writes:

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

Mark Dickinson

unread,
May 2, 2009, 12:45:47 PM5/2/09
to
On May 2, 4:12 pm, Esmail <ebo...@hotmail.com> wrote:
> Is there a Python construct to allow me to do something like
> this:
>
>     for i in range(-10.5, 10.5, 0.1):
>       ...

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

Esmail

unread,
May 2, 2009, 1:00:03 PM5/2/09
to pytho...@python.org
Thanks all, I appreciate the various suggestions and
caveats. Just wanted to make sure I'm not re-inventing
the wheel as Python seems to have already so much.

Cheers,
Esmail

bearoph...@lycos.com

unread,
May 2, 2009, 2:01:39 PM5/2/09
to
Esmail:

> Is there a Python construct to allow me to do something like
> this:
>     for i in range(-10.5, 10.5, 0.1):

Sometimes I use an improved version of this:
http://code.activestate.com/recipes/66472/

Bye,
bearophile

Esmail

unread,
May 2, 2009, 2:06:51 PM5/2/09
to pytho...@python.org

neat .. lots of code to study there. Thanks,
Esmail

Ben Finney

unread,
May 2, 2009, 7:48:34 PM5/2/09
to
Esmail <ebo...@hotmail.com> writes:

> 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

Esmail

unread,
May 2, 2009, 9:31:38 PM5/2/09
to pytho...@python.org
Ben Finney wrote:
>
> 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
> ...


Another nice solution stored away for use!

Thanks,
Esmail

Steven D'Aprano

unread,
May 3, 2009, 3:13:40 AM5/3/09
to


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

dusans

unread,
May 3, 2009, 3:25:32 AM5/3/09
to
>>> import numpy as np
>>> for i in np.arange(-10.5, 10.5, 0.1):
... print i

Zentrader

unread,
May 3, 2009, 4:41:49 PM5/3/09
to
There is no need for a function or a generator. A for() loop is a
unique case of a while loop
## for i in range(-10.5, 10.5, 0.1):
ctr = -10.5
while ctr < 10.5:
print ctr
ctr += 0.1

MRAB

unread,
May 3, 2009, 4:52:26 PM5/3/09
to pytho...@python.org
Python stores floats in binary, and 0.1 can't be held exactly as a
fractional binary number. Therefore it might be better to produce the
values as integers divided by 10:

for i in range(-105, 105):

i = i / 10.0
# do stuff here using i

Steven D'Aprano

unread,
May 3, 2009, 7:52:29 PM5/3/09
to


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

Gabriel Genellina

unread,
May 3, 2009, 8:05:33 PM5/3/09
to pytho...@python.org
En Sun, 03 May 2009 17:41:49 -0300, Zentrader <zentr...@gmail.com>
escribiᅵ:

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

Esmail

unread,
May 3, 2009, 9:41:23 PM5/3/09
to pytho...@python.org
Gabriel Genellina wrote:
>
> 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.


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?

Ben Finney

unread,
May 3, 2009, 9:58:12 PM5/3/09
to
Esmail <ebo...@hotmail.com> writes:

> 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

alex23

unread,
May 3, 2009, 10:48:20 PM5/3/09
to
On May 4, 11:41 am, Esmail <ebo...@hotmail.com> wrote:
> 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?

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

Sion Arrowsmith

unread,
May 5, 2009, 11:09:48 AM5/5/09
to
Gabriel Genellina <gags...@yahoo.com.ar> wrote:
>En Sun, 03 May 2009 17:41:49 -0300, Zentrader <zentr...@gmail.com>
>escribi�:

>> There is no need for a function or a generator. A for() loop is a
>> unique case of a while loop
>> ## for i in range(-10.5, 10.5, 0.1):
>> ctr = -10.5
>> while ctr < 10.5:
>> print ctr
>> ctr += 0.1
>
>Isn't so easy. You have representation errors and rounding errors here,
>and they accumulate. [ ... ]

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

J. Cliff Dyer

unread,
May 5, 2009, 1:11:43 PM5/5/09
to alex23, pytho...@python.org

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


0 new messages