Say I have two Python floats a
and b
, is there an easy way to find out how many representable real numbers are between the two in IEEE-754 representation (or whatever representation the machine used is using)?
views:
201answers:
4For positive numbers b > a > 0, the answer is approximately:
(2**52) ** (log(b,2) - log(a,2))
There are 52 bits of mantissa ( past the implied 1 ), multiplied by 2 raised to an exponent.
So there are 2**52 numbers in range [1:2) as in the range [1024:2048)
I don'tknow what you will be using this for - but, if both floats have the same exponent, it should be possible. As the exponent is kept on the high order bits, loading the float bytes (8 bytes in this case) as an integer and subtracting one from another should give the number you want. I use the struct model to pack the floats to a binary representation, and then unpack those as (C, 8 byte) long ints:
>>> import struct
>>> a = struct.pack("dd", 1.000000,1.000001)
>>> b = struct.unpack("ll",a)
>>> b[1] - b[0]
4503599627
>>> a = struct.pack("dd", 1.000000000,1.000000001)
>>> b = struct.unpack("ll",a)
>>> b[1] - b[0]
4503600
>>>
AFAIK, IEEE754 floats have an interesting property. If you have float f, then
(*(int*)&f + 1)
under certain conditions, is the next representable floating point number. So for floats a and b
*(int*)&a - *(int*)&b
Will give you the amount of floating point numbers between those numbers.
See http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm for more information.
I would look at the frexp function in the math module. The example below extracts the mantissa and converts it to an integer. The difference should be the number of floats between to the two values.
>>> math.frexp(1.1234567890)[0] * 2**53
5059599576307254.0
>>> math.frexp(1.12345678901)[0] * 2**53
5059599576352290.0
The following code should do it:
import math
import sys
def delta(x,y):
'''Return the number of floats between x and y.'''
x = float(x)
y = float(y)
if x == y:
return 0
elif x < y:
return -delta(y,x)
else:
x_mant, x_exp = math.frexp(x)
y_mant, y_exp = math.frexp(y)
x_int = int(x_mant * 2**(sys.float_info.mant_dig + x_exp - y_exp))
y_int = int(y_mant * 2**sys.float_info.mant_dig)
return x_int - y_int
print(delta(1.123456789, 1.1234567889999))
450
>>>