Next floating point number

Tim Peters tim.peters at gmail.com
Sat Dec 17 03:27:11 EST 2005


[Steven D'Aprano]
> I'm looking for some way to get the next floating point number after any
> particular float.
...
> According to the IEEE standard, there should be a routine like next(x,y)
> which returns the next float starting from x in the direction of y.
>
> Unless I have missed something, Python doesn't appear to give an interface
> to the C library's next float function. I assume that most C floating
> point libraries will have such a function.

While the C99 standard defines such a function (several, actually),
the C89 standard does not, so Python can't rely on one being
available.  In general, Python's `math` module exposes only standard
C89 libm functions, plus a few extras it can reliably and portably
build itself on top of those.  It does not expose platform-specific
libm functions.  You can argue with that policy, but not successfully
unless you take over maintenance of mathmodule.c <0.5 wink>.

> So I came up with a pure Python implementation, and hoped that somebody
> who had experience with numerical programming in Python would comment.

If you're happy with what you wrote, who needs comments ;-)  Here's a
careful, "kinda portable" implementation in C:

    http://www.netlib.org/toms/722

If you ignore all the end cases (NaNs, infinities, signaling underflow
and overflow, ...), the heart of it is just adding/subtracting 1
to/from the 64-bit double representation, viewing it as an 8-byte
integer.  That works fine for the IEEE-754 float representations (but
does not work for all float representations).

I've used this simple routine based on that observation, which ignores
all endcases, and only works if both input and result are >= 0:

"""
from struct import pack, unpack

def next(x, direction=+1):
    bits = unpack(">Q", pack(">d", x))[0]
    return unpack(">d", pack(">Q", bits + direction))[0]
"""

For example,

>>> next(0) # smallest denorm > 0
4.9406564584124654e-324
>>> next(_, -1) # should really signal underflow
0.0
>>> next(1)
1.0000000000000002
>>> next(1, -1)
0.99999999999999989
>>> next(1e100)
1.0000000000000002e+100
>>> next(1e100, -1)
9.9999999999999982e+099



More information about the Python-list mailing list