Next float?

Discussion in 'Python' started by Steven D'Aprano, Nov 22, 2007.

  1. Is there a simple, elegant way in Python to get the next float from a
    given one? By "next float", I mean given a float x, I want the smallest
    float larger than x.

    Bonus points if I can go in either direction (i.e. the "previous float"
    as well as the next).

    Note to maths pedants: I am aware that there is no "next real number",
    but floats are not reals.


    --
    Steven
    Steven D'Aprano, Nov 22, 2007
    #1
    1. Advertising

  2. Steven D'Aprano

    Alex Holkner Guest

    On Nov 22, 2007 2:04 PM, Steven D'Aprano
    <> wrote:
    > Is there a simple, elegant way in Python to get the next float from a
    > given one? By "next float", I mean given a float x, I want the smallest
    > float larger than x.
    >
    > Bonus points if I can go in either direction (i.e. the "previous float"
    > as well as the next).


    Not so elegant, but you could use ctypes to manipulate the bits
    (assumes machine uses IEEE 754 doubles for Python floats, I'm not sure
    if that's guaranteed on esoteric platforms):

    import ctypes

    def inc_float(f):
    # Get an int64 pointer to the float data
    fv = ctypes.c_double(f)
    pfv = ctypes.pointer(fv)
    piv = ctypes.cast(pfv, ctypes.POINTER(ctypes.c_uint64))

    # Check for NaN or infinity, return unchanged
    v = piv.contents.value
    if not ~(v & (11 << 52)): # exponent is all 1's
    return f

    if v == 1 << 63: # -0, treat as +0
    v = 1
    elif v & (1 << 63): # negative
    v -= 1
    else: # positive or +0
    v += 1

    # Set int pointer and return changed float
    piv.contents.value = v
    return fv.value

    def dec_float(f):
    # Get an int64 pointer to the float data
    fv = ctypes.c_double(f)
    pfv = ctypes.pointer(fv)
    piv = ctypes.cast(pfv, ctypes.POINTER(ctypes.c_uint64))

    # Check for NaN or infinity, return unchanged
    v = piv.contents.value
    if not ~(v & (11 << 52)): # exponent is all 1's
    return f

    if v == 0: # +0, treat as -0
    v = (1 << 63) | 1
    elif v & (1 << 63): # negative
    v += 1
    else: # positive
    v -= 1

    # Set int pointer and return changed float
    piv.contents.value = v
    return fv.value
    Alex Holkner, Nov 22, 2007
    #2
    1. Advertising

  3. Steven D'Aprano

    Mark T Guest

    "Steven D'Aprano" <> wrote in message
    news:p...
    > Is there a simple, elegant way in Python to get the next float from a
    > given one? By "next float", I mean given a float x, I want the smallest
    > float larger than x.
    >
    > Bonus points if I can go in either direction (i.e. the "previous float"
    > as well as the next).
    >
    > Note to maths pedants: I am aware that there is no "next real number",
    > but floats are not reals.
    >
    >
    > --
    > Steven


    Here's some functions to get the binary representation of a float. Then
    just manipulate the bits (an exercise for the reader):

    import struct

    def f2b(f):
    return struct.unpack('I',struct.pack('f',f))[0]

    def b2f(b):
    return struct.unpack('f',struct.pack('I',b))[0]

    >>> f2b(1.0)

    1065353216
    >>> hex(f2b(1.0))

    '0x3f800000'
    >>> b2f(0x3f800000)

    1.0
    >>> b2f(0x3f800001)

    1.0000001192092896
    >>> b2f(0x3f7fffff)

    0.99999994039535522

    -Mark
    Mark T, Nov 22, 2007
    #3
  4. Steven D'Aprano

    Paul Rubin Guest

    Steven D'Aprano <> writes:
    > Is there a simple, elegant way in Python to get the next float from a
    > given one? By "next float", I mean given a float x, I want the smallest
    > float larger than x.


    I think you have to do it by bit twiddling. But something like bisection
    search could come pretty close, for well-behaved values of x:

    def nextfloat(x):
    dx = (x, x/2.0)
    while x+dx[1] != x:
    dx = (dx[1], dx[1]/2.0)
    return dx[0]+x
    Paul Rubin, Nov 22, 2007
    #4
  5. Steven D'Aprano

    Robert Kern Guest

    Steven D'Aprano wrote:
    > Is there a simple, elegant way in Python to get the next float from a
    > given one? By "next float", I mean given a float x, I want the smallest
    > float larger than x.


    Courtesy of Tim Peters:

    http://mail.python.org/pipermail/python-list/2001-August/099152.html

    > Bonus points if I can go in either direction (i.e. the "previous float"
    > as well as the next).


    Left as an exercise for the reader. :)

    --
    Robert Kern

    "I have come to believe that the whole world is an enigma, a harmless enigma
    that is made terrible by our own mad attempt to interpret it as though it had
    an underlying truth."
    -- Umberto Eco
    Robert Kern, Nov 22, 2007
    #5
  6. Steven D'Aprano

    Robert Kern Guest

    Steven D'Aprano wrote:
    > Is there a simple, elegant way in Python to get the next float from a
    > given one? By "next float", I mean given a float x, I want the smallest
    > float larger than x.


    Heh:

    http://mail.python.org/pipermail/python-list/2005-December/357771.html

    --
    Robert Kern

    "I have come to believe that the whole world is an enigma, a harmless enigma
    that is made terrible by our own mad attempt to interpret it as though it had
    an underlying truth."
    -- Umberto Eco
    Robert Kern, Nov 22, 2007
    #6
  7. On Thu, 22 Nov 2007 00:44:34 -0600, Robert Kern wrote:

    > Steven D'Aprano wrote:
    >> Is there a simple, elegant way in Python to get the next float from a
    >> given one? By "next float", I mean given a float x, I want the smallest
    >> float larger than x.

    >
    > Heh:
    >
    > http://mail.python.org/pipermail/python-list/2005-December/357771.html


    Damn, I don't remember writing that!

    :-/



    --
    Steven.
    Steven D'Aprano, Nov 22, 2007
    #7
  8. "Steven D'Aprano" <steve..IS.cybersource.com.au> wrote:


    > Damn, I don't remember writing that!


    It is caused by drinking too much Alzheimer's Light.

    : - )

    - Hendrik
    Hendrik van Rooyen, Nov 22, 2007
    #8
  9. On Nov 22, 2007 4:04 AM, Steven D'Aprano
    <> wrote:
    > Is there a simple, elegant way in Python to get the next float from a
    > given one? By "next float", I mean given a float x, I want the smallest
    > float larger than x.
    >
    > Bonus points if I can go in either direction (i.e. the "previous float"
    > as well as the next).
    >
    > Note to maths pedants: I am aware that there is no "next real number",
    > but floats are not reals.
    > --
    > Steven


    You could use the library functions for floating-point math in mpmath
    (http://code.google.com/p/mpmath/), which support directed rounding.
    Load a floating-point number, add a tiny number and round in the
    wanted direction, then convert back to a Python float:

    >>> from mpmath.lib import *
    >>> eps = (1, -2000, 1) # 2**-2000, smaller than any finite

    positive IEEE 754 double
    >>> a = from_float(1.0, 53, ROUND_HALF_EVEN) # note: exact
    >>> to_float(fadd(a, eps, 53, ROUND_UP))

    1.0000000000000002
    >>> to_float(fsub(a, eps, 53, ROUND_DOWN))

    0.99999999999999989

    This currently probably doesn't work if the numbers are subnormal, however.

    Fredrik
    Fredrik Johansson, Nov 22, 2007
    #9
  10. On Nov 21, 11:48 pm, "Mark T" <> wrote:
    > Here's some functions to get the binary representation of a float. Then
    > just manipulate the bits (an exercise for the reader):
    >
    > import struct
    >
    > def f2b(f):
    > return struct.unpack('I',struct.pack('f',f))[0]
    >
    > def b2f(b):
    > return struct.unpack('f',struct.pack('I',b))[0]
    >
    > >>> f2b(1.0)

    > 1065353216
    > >>> hex(f2b(1.0))

    > '0x3f800000'
    > >>> b2f(0x3f800000)

    > 1.0
    > >>> b2f(0x3f800001)

    > 1.0000001192092896
    > >>> b2f(0x3f7fffff)

    >
    > 0.99999994039535522


    And it's worth noting that thanks to the way the floating-point format
    is designed, the 'bit-twiddling' is actually just a matter of adding
    or subtracting one from the integer representation above. This works
    all the way from zero, through subnormals, up to and including
    infinities.

    Mark (but not the same Mark)
    Mark Dickinson, Nov 22, 2007
    #10
  11. On Nov 22, 5:41 pm, Mark Dickinson <> wrote:
    > On Nov 21, 11:48 pm, "Mark T" <> wrote:
    >
    >
    >
    > > Here's some functions to get the binary representation of a float. Then
    > > just manipulate the bits (an exercise for the reader):

    >
    > > import struct

    >
    > > def f2b(f):
    > > return struct.unpack('I',struct.pack('f',f))[0]

    >
    > > def b2f(b):
    > > return struct.unpack('f',struct.pack('I',b))[0]

    >
    > > >>> f2b(1.0)

    > > 1065353216
    > > >>> hex(f2b(1.0))

    > > '0x3f800000'
    > > >>> b2f(0x3f800000)

    > > 1.0
    > > >>> b2f(0x3f800001)

    > > 1.0000001192092896
    > > >>> b2f(0x3f7fffff)

    >
    > > 0.99999994039535522

    >
    > And it's worth noting that thanks to the way the floating-point format
    > is designed, the 'bit-twiddling' is actually just a matter of adding
    > or subtracting one from the integer representation above. This works
    > all the way from zero, through subnormals, up to and including
    > infinities.
    >
    > Mark (but not the same Mark)


    And also worth noting that the 'f's above should probably be 'd's.
    For example, the following works on my machine for positive floats.
    Fixing this for negative floats is left as a not-very-hard exercise...

    >>> from struct import pack, unpack
    >>> def next_float(x): return unpack('d', pack('q', unpack('q', pack('d', x))[0]+1))[0]

    ....
    >>> next_float(1.0)

    1.0000000000000002

    Mark
    Mark Dickinson, Nov 22, 2007
    #11
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. bd
    Replies:
    0
    Views:
    605
  2. Deniz Bahar
    Replies:
    2
    Views:
    449
    Andrey Tarasevich
    Mar 9, 2005
  3. =?ISO-8859-2?Q?Miros=B3aw?= Makowiecki

    Reading of file by next of map file and by next of file descriptor.

    =?ISO-8859-2?Q?Miros=B3aw?= Makowiecki, Jul 10, 2007, in forum: C++
    Replies:
    1
    Views:
    778
    Alf P. Steinbach
    Jul 10, 2007
  4. Carsten Fuchs
    Replies:
    45
    Views:
    1,505
    James Kanze
    Oct 8, 2009
  5. Tad McClellan
    Replies:
    3
    Views:
    132
    Edward Wijaya
    May 13, 2004
Loading...

Share This Page