Technical Knowledge

目次

浮動小数

[コンピュータ]

浮動小数の誤差が発生するパターン。

0.1 が表現出来ない。(C++, Java 等)

double d1, d2;

d1 = 0.1;
d2 = 1.2 - 1.1;

if (d1 == d2) std::cout << "Equal" << std::endl;
else std::cout << "Not Equal" << std::endl;

結果

Not Equal

<2006-04-07 金>

浮動小数の仕組み。IEEE 754 での定義。

ビット定義

  • 単精度(32 ビット)
    • 符号部:1 ビット
    • 指数部:8 ビット
    • 仮数部:23 ビット
    • バイアス値:127
  • 倍精度(64 ビット)
    • 符号部:1 ビット
    • 指数部:11 ビット
    • 仮数部:54 ビット
    • バイアス値:1023

各項目説明

  • 符号部

    0 なら正、1なら負。

  • 指数部

    実際の 2 の指数にバイアス値を足したもの。

    • 単精度(32 ビット)

実際の指数 指数部
2 の 1 乗 1000 0000
2 の 0 乗 0111 1111
2 の -1 乗 0111 1110
  • 指数部が 255 の場合、
仮数部 説明
0 ∞INF
0 以外 NaN非数
  • 倍精度(64 ビット)

実際の指数 指数部
2 の 1 乗 100 0000 0000
2 の 0 乗 011 1111 1111
2 の -1 乗 011 1111 1110
  • 仮数部

    2 を基数として整数部分が 1 になるように正規化し、かつ整数部分の 1 を省略したもの。 入りきれない部分はデフォルトで最近偶数丸めで丸められる。最近偶数丸めは基本的には0捨1入。 0 は切り捨てて 1 は切り上げる。ただし、ぴったり 1 のとき、つまり端数が最後の桁のちょうど半分のときは、 丸めた後の数が偶数になるように切り上げたり切り捨てたりする。

IEEE 754 で「3.1」32 ビット浮動小数を表現

  • 3.1 を 2 進数化

2 の累乗 10 進数 元の値との差 引ければ 1
2 の2 乗 4 3.1 - 4 0
2 の1 乗 2 3.1 - 2 1
2 の0 乗 1 1.1 - 1 1
2 の-1 乗 0.5 0.1 - 0.5 0
2 の-2 乗 0.25 0.1 - 0.25 0
2 の-3 乗 0.125 0.1 - 0.125 0
2 の-4 乗 0.0625 0.1 - 0.0625 1
2 の-5 乗 0.03125 0.0375000000000001 - 0.03125 1
2 の-6 乗 0.015625 0.00625000000000009 - 0.015625 0
2 の-7 乗 0.0078125 0.00625000000000009 - 0.0078125 0
2 の-8 乗 0.00390625 0.00625000000000009 - 0.00390625 1
2 の-9 乗 0.001953125 0.00234375000000009 - 0.001953125 1
2 の-10 乗 0.0009765625 0.000390625000000089 - 0.0009765625 0
2 の-11 乗 0.00048828125 0.000390625000000089 - 0.00048828125 0
2 の-12 乗 0.000244140625 0.000390625000000089 - 0.000244140625 1
2 の-13 乗 0.0001220703125 0.000146484375000089 - 0.0001220703125 1
2 の-14 乗 0.00006103515625 0.0000244140625000888 - 0.00006103515625 0
2 の-15 乗 0.000030517578125 0.0000244140625000888 - 0.000030517578125 0
2 の-16 乗 0.0000152587890625 0.0000244140625000888 - 0.0000152587890625 1
2 の-17 乗 0.00000762939453125 0.00000915527343758882 - 0.00000762939453125 1
2 の-18 乗 0.000003814697265625 0.00000152587890633882 - 0.000003814697265625 0
2 の-19 乗 0.0000019073486328125 0.00000152587890633882 - 0.0000019073486328125 0
2 の-20 乗 0.00000095367431640625 0.00000152587890633882 - 0.00000095367431640625 1
2 の-21 乗 0.000000476837158203125 0.000000572204589932568 - 0.000000476837158203125 1
2 の-22 乗 0.000000238418579101562 0.0000000953674317294428 - 0.000000238418579101562 0
2 の-24 乗 0.0000000596046447753906 0.0000000953674317294428 - 0.0000000596046447753906 1
2 の-25 乗 0.0000000298023223876953 0.0000000357627869540522 - 0.0000000298023223876953 1
…….

よって、011.0001100110011001100110011 となる。

  • 符号部

    3.1 > 0 なので 0。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
0 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  • 指数部

    整数部分が 1 桁となるように正規化するため、2 の 1 乗。 01.10001100110011001100110011 * 2 の 1 乗@<br /> 実際の指数 1 に 127 を足したものを 8 ビット2進数で表現するので 1000 0000。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
0 1 0 0 0 0 0 0 0 * * * * * * * * * * * * * * * * * * * * * * *
  • 仮数部

    正規化した 01.10001100110011001100110011 * 2 の 1 乗 の整数 1 桁目を省略した 23 ビット分。 24 ビット以降も 0110… と続くため 0 捨 1 入 となり。24 ビット目以降を切り捨てて 100 0110 0110 0110 0110 0110。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
0 1 0 0 0 0 0 0 0 1 0 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0

C++ で 2 進数表示

  #define TOP_BIT 0x80

  int main(int argc, char** argv)
  {
float f = 3.1f;
char* p = (char*)&f + sizeof(f) - 1;    // リトルエンディアン対応

for (int i = 0; i < sizeof(f); ++i, --p)    // リトルエンディアン対応
{
  char ch = *p;
  for (int j = 0; j < 8; ++j, ch <<= 1)
  {
    if (ch & TOP_BIT) cout << "1";
    else cout << "0";
  }
  cout << " ";
}
    return EXIT_SUCCESS;
  }

<2008-02-28 木>

浮動小数の誤差の尺度。

ある実数 a が正規化の分を含まない仮数の桁数が p、かつ指数が e で表せるならば、a の 1 ULP(unit in ther last place) は、

ULP(a) = 2 ** (e - p) (2 の e - p 乗)

である。


<2010-11-23 火>

結合法則、交換法則が成り立たない場合がある。

変数の double より CPU 内の double のほうがビット長が長くてその長い部分に格納されてる値が初期化されないまま使い回されて同じ計算の結果が異なってしまう。

double a = ...;
double b = ...;
double c = a + b;
double d = b + a;
c != d;

<2011-08-04 木>

補数

補数による負数表現。

10 進数 12 の補数は、12 より大きくなる 10 進数の最少冪乗の100(10 の 2 乗)から 12 を引いたもの。100 - 12 = 88 が 10 の補数となる。@<br /> 9 の補数(10 - 1 の補数であり 9 進数の補数とは違う) で求める場合、各桁の 9 -1 = 8, 9 - 2 = 7 の値 87 に 1 を加え 88 となる。 1 バイト表現 2 進数 12(0000 1100) の補数は、12 より多くなる 2 進数の最少冪乗の 256 (1 0000 0000) から 12(0000 1100) を引いたもの。-12(1111 0100) が 2 の補数となる。この場合、最上位ビットを符号ビットとみなしているため -12 となる。@<br /> オーバフローを考えない場合、各ビットを反転させ 1 を加えることで求めることができる。12(0000 1100) を反転し(1111 0011) 1 を加えると(1111 0100) となる。


<2010-11-23 火>

Date: 2021-10-03