新人教育用資料です
指数形式とは、例えば「12345」を「1.2345×10の4乗(1.2345E4)」「0.012345」を「1.2345×10の-2乗(1.2345E-2)」というように表す形式のことである。「整数部○桁/小数部△桁」というように、あらかじめ整数部と小数点以下の有効桁数を固定して表現する「固定小数点」に対し、小数点が有効桁数の間で浮動することからこう呼ばれており、少ないビット数で小さな値や大きな値を効率よく扱えるため、コンピュータの実数演算で広く用いられている。
「1.2345×10の4乗」の「1.2345」を「仮数部」、「4」を「指数部」、「10」を「基数」という。
下図は単精度(float)の場合のレイアウト例。
浮動小数点形式の標準規格である「IEEE 754」の単精度浮動小数点数では、仮数部(Mantissa)に23bit、指数部(Exponent)に8bit(基数は2)、符号に1bitの計32bitで、1.40129846E-45〜3.40282347E38(正の値)の値を表すことができる。ちなみにビット数を2倍の64ビット(仮数部52、指数部11ビット)にしたものが倍精度浮動小数点数である。
ノーマライズ(正規化)とは、桁数が一番上のものだけが整数部になるように小数点の位置を調整することを意味する。 仮数+指数という表現の場合、指数の取り方で何通りもの書き方ができてしまうため、それを一つに統一するため。
10進表現 | 2進表現 | 2進で仮数+指数で表現 |
3 | 11 | 11 x 2^0, 1.1 x 2^1, 0.11 x 2^2, … |
10進の3を2進で仮数+指数の形式で書くときには 1.1 x 2^1 (1.1x2の1乗)と書くように決めておく、ということ。
表現したい数(10進) | 符号 | 指数部(2進) | 仮数部(2進) | 全体(16進) |
0.5 | 0 | 0111 1110 | 0 | 3f 00 00 00 |
1 | 0 | 0111 1111 | 0 | 3f 80 00 00 |
2 | 0 | 1000 0000 | 0 | 40 00 00 00 |
3 | 0 | 1000 0000 | 1 | 40 40 00 00 |
4 | 0 | 1000 0001 | 0 | 40 80 00 00 |
5 | 0 | 1000 0001 | 01 | 40 A0 00 00 |
6 | 0 | 1000 0001 | 1 | 40 C0 00 00 |
7 | 0 | 1000 0001 | 11 | 40 E0 00 00 |
こんな感じになる。
using System; using System.IO; class Class1 { [STAThread] static void Main(string[] args) { float f = 4f; FileStream fs = new FileStream("test.dmp", FileMode.Create); BinaryWriter w = new BinaryWriter(fs); w.Write(f); w.Close(); fs.Close(); } }
IntelアーキテクチャのCPUはリトルエンディアンなのでメモリ上ではバイトオーダーが逆転する点に注意。
指数であるために、大小幅広い値をとれるが、精度はあくまで仮数部のビット数止まりであり、その性質上、演算には丸め誤差がつきものとなる。また、10進数ではないために、10進の有限小数でも正確に表現できない場合もある(例えば0.1)。
これは例えば以下のようなプログラムを書いて見ると実感できる。
using System; class Class1 { [STAThread] static void Main(string[] args) { float f = 0.1f; float f2 = 0; for(int i = 0; i < 10000; i++ ) { f2 += f; } Console.WriteLine(f2); Console.ReadLine(); } } 実行結果: 999.9029
Tutorial: Floating-Point Binary
http://www.nuvisionmiami.com/books/asm/workbook/floating_tut.htm
IEEE Standard 754 Floating Point Numbers
http://research.microsoft.com/~hollasch/cgindex/coding/ieeefloat.html