472,131 Members | 1,388 Online

# Next float?

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
Nov 22 '07 #1
10 2886 On Nov 22, 2007 2:04 PM, Steven D'Aprano
<st****@remove.this.cybersource.com.auwrote:
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
Nov 22 '07 #2

"Steven D'Aprano" <st****@REMOVE.THIS.cybersource.com.auwrote in message
news:pa*********************@REMOVE.THIS.cybersour ce.com.au...
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))

def b2f(b):
return struct.unpack('f',struct.pack('I',b))
>>f2b(1.0)
1065353216
>>hex(f2b(1.0))
'0x3f800000'
>>b2f(0x3f800000)
1.0
>>b2f(0x3f800001)
1.0000001192092896
>>b2f(0x3f7fffff)
0.99999994039535522

-Mark

Nov 22 '07 #3
Steven D'Aprano <st****@REMOVE.THIS.cybersource.com.auwrites:
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 != x:
dx = (dx, dx/2.0)
return dx+x
Nov 22 '07 #4
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/pyt...st/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
an underlying truth."
-- Umberto Eco

Nov 22 '07 #5
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/pyt...er/357771.html

--
Robert Kern

"I have come to believe that the whole world is an enigma, a harmless enigma
an underlying truth."
-- Umberto Eco

Nov 22 '07 #6
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/pyt...er/357771.html
Damn, I don't remember writing that!

:-/

--
Steven.
Nov 22 '07 #7
On Nov 22, 2007 4:04 AM, Steven D'Aprano
<st****@remove.this.cybersource.com.auwrote:
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
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
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
Nov 22 '07 #8
On Nov 21, 11:48 pm, "Mark T" <nos...@nospam.comwrote:
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))

def b2f(b):
return struct.unpack('f',struct.pack('I',b))
>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)
Nov 22 '07 #9
On Nov 22, 5:41 pm, Mark Dickinson <dicki...@gmail.comwrote:
On Nov 21, 11:48 pm, "Mark T" <nos...@nospam.comwrote:
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))
def b2f(b):
return struct.unpack('f',struct.pack('I',b))
>>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))+1))
....
>>next_float(1.0)
1.0000000000000002

Mark
Nov 22 '07 #10
"Steven D'Aprano" <steve..IS.cybersource.com.auwrote:

Damn, I don't remember writing that!
It is caused by drinking too much Alzheimer's Light.

: - )

- Hendrik

Nov 23 '07 #11

### This discussion thread is closed

Replies have been disabled for this discussion.

### Similar topics

 10 posts views Thread by george | last post: by 3 posts views Thread by David Ross | last post: by 13 posts views Thread by Peter Ammon | last post: by 9 posts views Thread by Steven D'Aprano | last post: by 22 posts views Thread by ashkaan57 | last post: by 6 posts views Thread by Harlan Messinger | last post: by reply views Thread by removeps-groups | last post: by 15 posts views Thread by dlite922 | last post: by 5 posts views Thread by p309444 | last post: by 3 posts views Thread by isladogs | last post: by reply views Thread by beacampos | last post: by reply views Thread by isladogs | last post: by 1 post views Thread by beacampos | last post: by reply views Thread by pddon | last post: by reply views Thread by bakertaylor28 | last post: by reply views Thread by leo001 | last post: by reply views Thread by antdb | last post: by 5 posts views Thread by Bright1Light | last post: by