Скажем, у меня есть два поплавка Python a
и b
, есть ли простой способ узнать, сколько представляемых реальных чисел находится между ними в представлении IEEE-754 (или каким-либо другим представлением, которое использует машина)?
Количество поплавков между двумя поплавками
Ответ 1
Я не знаю, для чего вы это используете, но если оба поплавка имеют одинаковый показатель, это должно быть возможно. Поскольку экспонента хранится на битах высокого порядка, загрузка байтов с плавающей запятой (в этом случае 8 байтов) в виде целого числа и вычитание одного из другого должно указывать нужный вам номер. Я использую модель структуры для упаковки поплавков в двоичное представление, а затем распаковываю их как (C, 8 байт) длинных 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
>>>
Ответ 2
Поплавки AFAIK, IEEE754 имеют интересное свойство. Если у вас есть float f, то
(*(int*)&f + 1)
при определенных условиях, является следующим представимым числом с плавающей запятой. Итак, для float a и b
*(int*)&a - *(int*)&b
Дает вам количество чисел с плавающей запятой между этими числами.
Подробнее см. http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm.
Ответ 3
Для положительных чисел b > a > 0 ответ примерно:
(2**52) ** (log(b,2) - log(a,2))
Есть 52 бита мантиссы (минус подразумеваемая 1), умноженная на 2, поднятых до экспоненты.
Таким образом, в диапазоне [1: 2] есть 2 ** 52 номера в диапазоне [1024: 2048]
Ответ 4
Я бы посмотрел на функцию frexp в математическом модуле. В приведенном ниже примере извлекается мантисса и преобразуется в целое число. Разница должна заключаться в количестве поплавков между двумя значениями.
>>> math.frexp(1.1234567890)[0] * 2**53
5059599576307254.0
>>> math.frexp(1.12345678901)[0] * 2**53
5059599576352290.0
Следующий код должен сделать это:
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
>>>