小数の表現

2進表記で小数を表すのも、十進表記に合わせて考えます。

十進表記

0.345

は次の意味になります。

3 × 0.1 + 4 × 0.01 + 5 × 0.001

これをもっと十進法ということを意識するために書き換えると

3 × 10-1 + 4 × 10-2 + 5 × 10-3

となります。10-nは10でn回割るという意味です。

二進表記

二進表記で書いた数

0.111

これは次のような意味になります

1 × 0.5 + 1 × 0.25 + 1 × 0.125

これは次のように考えた方がわかりやすいでしょう。十進の10の代わりに2を入れたものです。

1 × 2-1 + 1 × 2-2 + 1 × 2-3

2-nの値は次のようになっており、整数より複雑です。

二進表現 十進表現
2-10.10.5
2-20.010.25
2-30.0010.125
2-40.00010.0625
2-50.000010.03125
2-60.0000010.015265
2-70.00000010.0078125
2-80.000000010.00390625

十進表記で見慣れた小数も二進表記ではその多くが循環小数になり有限桁では正確に表せません。

十進表現 二進表現
0.10.000110011001100…
0.20.001100110011001…
0.30.010011001100110…
0.40.011001100110011…
0.50.1
0.60.100110011001100…
0.70.101100110011001…
0.80.110011001100110…
0.90.111001100110011…

コンピュータでの表現

二進でも十進でも循環小数を有限桁で表現しようとすると不正確になるのは同じです。しかし十進の小数を二進で表現すると循環小数になることが多く根本的に問題を抱えていることになります。

固定小数点数

固定小数点で表現する方式。ビット列のどこかに小数点があると決めて計算します。

たとえば、簡単のために4ビットで考えて、右から1桁目と2桁目の間に小数点があるとすれば、

0111

は、11.1のことで、十進にすると3.5となります。

この表記法では(負の数は考えないとして)0から7.5までしか表現できないことからわかるように表現できる範囲が狭くなります。

コンピュータで小数を扱うのは普通次の浮動小数点数です。

浮動小数点数

浮動小数点数は単に小数部を持つ数だけではなく、整数型の表現の限界を越える大きな数を扱う方法としても重要です。

科学技術の分野では数値の次のように表現します。

4.6875×103

これは4.6875の小数点を3桁右に移動させた数のことで、4687.5のことです。

この時4.6875仮数部 3 を 指数部 10 を 基数 といいます。

(仮数部)×(基数)(指数部)

基数を2にし、仮数部も指数部も二進で表現するのが浮動小数点数です。

たとえば 3.5 は二進表現では 11.1 でしたが、

1.11×21

とします。基数の2だけ二進表現でないので変ですが、実際のデータでは2は書きません。

十進表現では10を掛けることで小数点が1桁右に移動しますが二進表現では2を掛けることで小数点が1桁右に移動しますから 21 が小数点が1桁右に移動することを指示しています。

浮動小数点数の表現方法もさらにいくつかの種類がありますが、一番多く使われているIEEE754(アイトリプルイー、The Institute of Electrical and Electronics Engineers, Inc.)を説明します。

IEEE754 32ビット(単精度)の場合

IEEE754は浮動小数点数の代表的な規格です。

正負の符号に1ビット、指数部に8ビット、仮数部に23ビット使います。

± 指数部(8) 仮数部(23)
0 1 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
符号
2の補数で表現される整数と同じく正が0、負が1
指数部
127を加えた整数(エクセス127)で表します。指数部が負のときの計算を楽にするためのようです
仮数部
指数を調整し1.で始まるようにします。十進表現と異なり必ず1で始まりますから、この1を省略します。

二進表現での精度(計算の細かさ)は23+1で24ビットです。十進表現での精度に直すと7桁の精度です。

例1

4.6875はどうなるでしょうか。

4.6875 = 4 + 0.5 + 0.125 + 0.0625

ですから、二進表記は

100.1011

です。これを1.で始まる仮数部と指数部にします。

1.001011×210

指数部に127、二進では 1111111を足します

  1111111
+      10
 10000001

仮数部は最初の1を省略し小数点以下だけを書く

± 指数部(8) 仮数部(23)
0 1 0 0 0 0 0 0 1 0 0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

例2 -0.1の場合

-0.1はどうなるでしょうか。

まず、マイナスなので符号を1にします。

0.1は上にあるように循環小数になるのでした。

0.000110011001100…

です。これを1.で始まる仮数部と指数部にします。

1.10011001100×2-100

指数部に127、二進では 1111111を足します

  1111111
-     100
  1111011

仮数部は最初の1を省略し小数点以下だけを書く

± 指数部(8) 仮数部(23)
1 0 1 1 1 1 0 1 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 1

循環小数なので入りきらないのですが、近い方を採用します。

最後の部分だけ注目しますと、

…1100      切り捨てた場合
…110011001100… 真の値
…1101      切り上げた場合

近いのは…1101 なので、切り上げています。

IEEE754 64ビット(倍精度)の場合

最近は浮動小数点数といえば64ビットを使うことが普通になりました。ビット数が多くなるだけでやり方は同じです。

正負の符号に1ビット、指数部に11ビット、仮数部に52ビット使います。

± 指数部(11) 仮数部(52)
0 1 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

二進表現での精度(計算の細かさ)は52+1で53ビットです。十進表現での精度に直すと15桁の精度です。

符号
2の補数で表現される整数と同じく正が0、負が1
指数部
1023を加えた整数(エクセス1023)で表します。指数部が負のときの計算を楽にするためのようです
仮数部
指数を調整し1.で始まるようにします。十進表現と異なり必ず1で始まりますから、この1を省略します。

精度を上げる

整数

符号付きの整数で数値の範囲、あるいは精度は次の通りです。

バイト数最小値最大値
1 -128127
2 -32768 32767
4 -21474836482147483647
8 -92233720368547758089223372036854775807

浮動小数

IEEE754の単精度(4バイト=32bit)、倍精度(8バイト=64bit)で表現できる数値の精度は次の通りです。

形式 有効数字の10 進表現 最大の正の数 最小の正の数(精度維持) 最小の正の数
単精度 6-9桁 3.402... ×10+38 1.175... ×10-38 1.402... ×10-45
倍精度 15-17桁 1.797... ×10+308 2.225... ×10-308 4.940... ×10-324

有効数字6桁の精度とは長さを、1.23456km まで測る時の精度です。これは1234mと56cmのことですから、1kmの長さをcmの詳しさまで測ったということです。1kmから1cmまで6桁あるので有効数字6桁といいます。もしも123.456kmの場合は123kmと456mですからmの所まで測って6桁の精度ということになります。

科学技術の計算ではより精度の高い計算が必要な時は使用するビットを増やして計算をします。たとえば倍精度の2倍のビット数を使う4倍精度というものがあります。循環小数でも桁数が多ければより正確になるという考え方です。科学技術の分野ではこれで問題ありません。コンピュータの得意な2進法の中で計算しますから高速に計算できます。

2進法で浮動小数の計算をする場合、十進で正確に表現できる数も二進で循環小数になるという現象などで計算結果が微妙に変わってくる場合があります。また四捨五入をしたはずなのに結果が異なるということもあります。お金の計算で小数が入ってくる利息の計算などではこれではまずいので対策が必要です。

数値の内部表現を10進法を使う二進化十進法やBigDecimal(Javaの場合),割り算を分数にしたまま表現する方法などプログラム言語ごとに用意されていますので必要に応じて調べて使うようにします。

聖愛中学高等学校
http://www.seiai.ed.jp/
Jun. 2009