[Python-Dev] basenumber redux

Adam Olsen rhamph at gmail.com
Wed Jan 18 00:29:35 CET 2006


On 1/17/06, Alex Martelli <aleaxit at gmail.com> wrote:
> Being able to change imaplib to use basenumber instead of (int, float)
> won't make it SIMPLER, but it will surely make it BETTER -- why should
> a long be rejected, or a Decimal,
> for that matter?

Because there's no guarantee that they'll produce correct results? 
All number types are approximations of true numbers, and they all
behave wrong in creative ways.

For example:

def xrange(start, stop, step):
  i = start
  while i < stop:
    yield i
    i += step

This works fine so long as you only give it int as input, and has no
maximum value.

>>> for i in xrange(2**53, 2**53+3, 1): print i
...
9007199254740992
9007199254740993
9007199254740994

Float inputs also work so long as you don't get large enough to
provoke rounding.  However, as soon as you do...

>>> for i in xrange(2**53, 2**53+3, 1.0): print i
...
9007199254740992
9.00719925474e+15
9.00719925474e+15
9.00719925474e+15
9.00719925474e+15
<snip>
9.00719925474e+15
9.00719925474e+15
974e+15
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
KeyboardInterrupt

The function fails.  Floating point, despite being a "number" and
supporting the "number interface", does not behave close enough to
what the programmer desires to work for all values.  There might be a
way to handle floats specially that a mathematician may understand,
but the only way I know of is to convert to int at the start of the
function.

def xrange(start, stop, step):
  start, stop, step = int(start), int(stop), int(step)
  i = start
  while i < stop:
    yield i
    i += step

>>> for i in xrange(2**53, 2**53+3, 1.0): print i
...
9007199254740992
9007199254740993
9007199254740994

That works so long as the floats are all integral values. 
Unfortunately a non-integral value will get truncated silently.  An
explicit check for equality after the conversion would have to be
added, or Guido's __index__ could be used, but __index__ seems
misnamed for this usage.

Another approach would be changing operations involving floats to
return intervals instead.  The high end of the interval would continue
to count up when rounding is provoked, and would raise an exception
when the i < stop is executed (due to being ambiguous).  Once float
uses intervals you could state that all number types are expected to
use intervals in the face of inexactness (and those who don't behave
as expected would have unexpected results.)

--
Adam Olsen, aka Rhamphoryncus


More information about the Python-Dev mailing list