Warning: Undefined variable $position in /home/pystyles/pystyle.info/public_html/wp/wp-content/themes/lionblog/functions.php on line 4897

浮動小数点数 (IEEE754) について解説

浮動小数点数 (IEEE754) について解説

概要

IEEE754 で規定されている浮動小数点数について解説します。

Advertisement

浮動小数点数

浮動小数点数 (floating point numbers) は、固定長の仮数部と指数部を持つ、実数の近似表現法です。

$$ \text{significand} \times \text{base}^\text{exponent} $$

IEEE 754

正式名称は IEEE Standard for Binary Floating-Point Arithmetic です。この規格では2進浮動小数点数を以下のように表現します。

$$ \pm f \times 2^e $$

$f$ は有効数字を構成する部分で、仮数 (mantissa / significand / fraction) といいます。 このままでは、

$$ (1.00)_2 \times 2^0 = (0.10)_2 \times 2^1 = (0.01)_2 \times 2^2 $$

のようにある数値に対して、複数の表現方法が存在するので、仮数の整数部は1にすると約束することで、浮動小数点表現を一意にします。この取り決めに従う浮動小数点数を正規化浮動小数点数といいます。

符号化方法

浮動小数点数は符号部、指数部、仮数部の3つの要素によって特徴付けられるビット列で符号化します。

符号部 符号付指数部 仮数部
$s$ $e_1 e_2 \cdots e_q$ $f_1 f_2 \cdots f_p$
$1$ bit $q$ bit $p$ bit

符号部

0で正、1で負を表します。

仮数部 (mantissa / significand / fraction)

仮数 $f$ は $f = (1.b_1 b_2 \cdots b_p)_2, b_i = 0, 1$ という $p + 1$ 桁のビット列で表します。正規化浮動小数点数では先頭ビットは必ず1なので、データ上は $p$ ビットで表します。このことをけち表現といいます。

指数部 (signed exponent / biased exponent)

冪指数 $e$ は負の値もとりますが、$e + bias$ のように値にある定数 $bias$ を加算して非負の整数で表現します。このことをバイアス表現または下駄履き表現といいます。

例えば倍精度の場合、値 $e$ を表現する場合、$e + 1023$ という値で表っします。

実際の値 -1022 -2021 $\cdots$ 1022 1023
バイアス表現 1 2 $\cdots$ 2045 2046

倍精度のバイアス表現

冪指数 $e$ の最小値、最大値をそれぞれ $e_{min}, e_{max}$ とすると、

$(00 \cdots 0)_2 – bias$ 特殊な値を表すのに使用
$(00 \cdots 1)_2 – bias$ $e_{min}$
$\vdots$
$(11 \cdots 10)_2 – bias$ $e_{max}$
$(11 \cdots 1)_2 – bias$ 特殊な値を表すのに使用

であるため、

$$ e_{min} = 1 – bias e_{max} = (2^q – 1) – 1 – bias = 2^q – 2 – bias $$

となります。

ビット列が表す浮動小数点数

符号部 符号付指数部 仮数部
$s$ $e_1 e_2 \cdots e_q$ $f_1 f_2 \cdots f_p$
$1$ bit $q$ bit $p$ bit

このビット列で表される浮動小数点数は次のようになります。

$$ x = (-1)^s \times (1.f_1 f_2 \cdots f_p)_2 \times 2^{(e_1 e_2 \cdots e_q)_2 – bias} $$

ただし、$(\cdot)_2$ は2進数表現であることを意味しています。

正規化浮動小数点数の範囲

正規化浮動小数点数の0に最も近い値を $N_{min}$、0から最も遠い値を $N_{max}$ とすると、

$$ \begin{aligned} N_{min} &= (1.00\cdots0)_2 \times 2^{e_{min}} = 2^{e_{min}} \\ N_{max} &= (1.11 \cdots 1)_2 \times 2^{e_{max}} = (2 – 2^{-p}) \times 2^{e_{max}} \end{aligned} $$

となります。

正規化浮動小数点数の範囲

特殊な数について

$e + bias$ の値が $(00 \cdots 0)_2 = 0$ 及び $(11 \cdots 1)_2 = 2^q – 1$ の場合は、以下の特殊な値を表すために予約されています。

種類 符号部 指数部 仮数部
$s = 0, 1$ $e + bias = (00 \cdots 0)_2$ $f = (00 \cdots 0)_2$
非正規化数 $s = 0, 1$ $e + bias = (00\cdots0)_2$ $f \ne (00\cdots0)_2$
無限 $s = 0, 1$ $e + bias = (11\cdots1)_2$ $f = (00\cdots0)_2$
NaN $s = 0, 1$ $e + bias = (11\cdots1)_2$ $f \ne (00\cdots0)_2$

零 (zero)

符号付きで $\pm 0$ を表します。

非正規化数 (denormalized number (旧称) / subnormal number)

正規化浮動小数点数の0とそれに最も近い値 $\pm N_{min} = 2^{e_{min}}$ は間隔が空いているため、$(0.f_1 f_2 \cdots f_p)_2 \times 2^{e_{min}}$ という形式で表す浮動小数点数を $|x| < N_{min}$ に作成します。先頭ビットが1でないので、これを非正規化数といいます。このとき有効桁数が正規化浮動小数点数と比較して1桁少ないことに注意します。 非正規化数は間隔が $\pm (0.00 \cdots 01)_2 \times 2^{e_{min}}$ の固定小数点数です。

無限 (infinity)

符号付きで $\pm \infty$ を表します。無限は演算の結果、正規化浮動小数点数で表せる範囲を超えてしまった場合に生成される数です。

NaN (Not a Number)

NaN は $0 / 0$ や $\sqrt{-1}$ など定義されない演算結果として生成される特殊な数です。$NaN$ との等号での比較は常に偽となるように定められているので、値が NaN かどうか判定する場合に等号で判定することはできないので注意してください。

In [1]:
float("nan") == float("nan")
False

計算機イプシロン / マシンイプシロン (machine epsilon)

計算機イプシロンは $1$ と $1$ より大きい最小の浮動小数点数との距離です。 $(1.00 \cdots 0)_2 \times 2^0$ の次に大きい値は、$(1.00 \cdots 1)_2 \times 2^0$ であるから、その差は $\varepsilon = 2^{-p}$ になります。

単精度、倍精度

IEEE754 では32ビットで表す単精度 (single precision)及び64ビットで表す倍精度 (double precision)が規定されている。符号化した際の各ビット数は以下のようになります。

単精度 倍精度
符号部のビット数 $s$ 1 1
仮数部のビット数 $p$ 23 52
指数部のビット数 $q$ 8 11
全体のビット数 $1 + p + q$ 32 64
バイアス $bias$ 127 1023

単精度、倍精度の各種定数は以下のようになります。

単精度 倍精度
$e_{min}$ -126 -1022
$e_{max}$ 127 1023
$N_{min}$ $82^{-126} \approx 1.18 \times 10^{-38}$ $2^{-1022} \approx 2.23 \times 10^{-308}$
$N_{max}$ $2^{128} – 2^{104} \approx 3.40 \times 10^{38}$ $2^{1024} – 2^{971} \approx 1.80 \times 10^{308}$
$\varepsilon$ $2^{-23} \approx 1.19 \times 10^{-7}$ $2^{-52} \approx 2.22 \times 10^{-16}$
非正規化数 $2^{-149} \approx 1.40 \times 10^{-45}$ $2^{-1074} \approx 5.00 \times 10^{-324}$

単精度、倍精度の使い分け

倍精度のほうが精度はいいですが、値を表すのに必要なメモリ量が倍になります。数値計算は基本的には倍精度で行うことが一般的ですが、ディープラーニングや 3DCG のように大量の数値を扱い、精度は倍精度ほどは必要ない分野では単精度が使われます。

Python で確認する

Python の浮動小数点型 float は倍精度です。

sys.float_info – 浮動小数点の情報を取得する

sys.float_info から浮動小数点数の情報が取得できます。

In [2]:
import sys

info = sys.float_info

print("浮動小数点数で正確に表現できる10進数の桁数", info.dig)
print("計算機イプシロン", info.epsilon)
print("正の方向で0から最も遠い値", info.max)
print("正の方向で0に最も近い値", info.min)
print("指数部の基数", info.radix)
print("丸めモード", info.rounds)
浮動小数点数で正確に表現できる10進数の桁数 15
計算機イプシロン 2.220446049250313e-16
正の方向で0から最も遠い値 1.7976931348623157e+308
正の方向で0に最も近い値 2.2250738585072014e-308
指数部の基数 2
丸めモード 1

無限、NaN を作成する

In [3]:
nan = float("nan")
pos_inf = float("inf")
neg_inf = float("-inf")

print(nan, type(nan))
print(pos_inf, type(pos_inf))
print(neg_inf, type(neg_inf))
nan <class 'float'>
inf <class 'float'>
-inf <class 'float'>

math モジュールの浮動小数点数関係の関数

  • math.isfinite: 無限または NaN でない場合は True を返します。
  • math.isinf: 無限の場合は True を返します。
  • math.isnan: NaN の場合は True を返します。
  • math.frexp(x): 小数を仮数部と指数部に分解します。
  • math.ldexp(x, i): 仮数部と指数部から小数を構成します。
In [4]:
import math

nan = float("nan")

print(math.isnan(nan))
print(float("nan") == nan)  # NaN の等号の比較はダメ
True
False
In [5]:
x = 1.23

sig, exp = math.frexp(x)
print(sig, exp)

y = math.ldexp(sig, exp)
print(x == y)
0.615 1
True
In [ ]:
x = np.float32(1).tobytes()


def access_bit(data, num):
    base = int(num // 8)
    shift = int(num % 8)
    return (data[base] >> shift) & 0x1


aa = ["".join([str(access_bit(x, j + i * 8)) for j in range(8)][::-1]) for i in range(len(x))][::-1]
# ['11111100', '00110001', '00110011', '10110011']
[int(a, base=2) for a in aa]
# 11111110 00110011 00110011 001101
"".join(aa)

参考