2 つの Python floata
とb
があるとします。IEEE-754 表現 (または使用されているマシンが使用している表現) で 2 つの間に表現可能な実数がいくつあるかを簡単に調べる方法はありますか?
4 に答える
AFAIK、IEEE754 フロートには興味深い特性があります。float f がある場合、
(*(int*)&f + 1)
特定の条件下では、次の表現可能な浮動小数点数です。したがって、float a と b の場合
*(int*)&a - *(int*)&b
これらの数値の間の浮動小数点数の量が得られます。
詳細については、 http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htmを参照してください。
これを何に使用するのかはわかりませんが、両方の浮動小数点数が同じ指数を持つ場合は可能です。指数は上位ビットに保持されるため、float バイト (この場合は 8 バイト) を整数としてロードし、別のバイトから 1 を減算すると、必要な数値が得られます。構造体モデルを使用して float をバイナリ表現にパックし、(C、8 バイト) long int として展開します。
>>> 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
>>>
正の数 b > a > 0 の場合、答えはおよそ次のようになります。
(2**52) ** (log(b,2) - log(a,2))
52 ビットの仮数 (暗黙の 1 を過ぎたもの) があり、指数に累乗された 2 が乗算されます。
したがって、範囲 [1:2) には範囲 [1024:2048) のように 2**52 個の数値があります。
math モジュールの frexp 関数を見てみましょう。次の例では、仮数を抽出して整数に変換します。差は、2 つの値の間の float の数になります。
>>> 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
>>>