float型についてわかったことをまとめる

  • このエントリーをはてなブックマークに追加

スポンサーリンク

※サイト運営にサーバーは必須です※
ヘテムル は大型サイトの作成に向いています~

はじめに

float型が32ビットで表現されることは知っていました。

しかし、どうやって小数の数字を扱っているのか、あまりよくわかっていませんでした。

この記事では、float型について私がわかったことを整理します。

主な参考サイト

※間違いがあったら、コメント欄で指摘していただけると助かります。

32ビットの内訳

1ビット:符号
8ビット:指数部
23ビット:仮数部

符号(1ビット)

-、+かで0か1が割り振られる。

指数部(8ビット)

8ビットなので、byte型をイメージすると、0~255の256通りの表現を行うことができます。

sbyte型をイメージすると、2の(-128乗)~2の(127乗)まで表現できるような気がしますが、これは間違いです。

256通りの内、0と255の2通りに関しては以下の用途で予約されており、使えません。

「0」の場合:数字の0と非正規化数を表現するために使われます。

※非正規化数について詳しく知りたい場合は、以下のwikiのページで詳しく説明されています。
非正規化数(wiki)

255の場合:無限大または NaNを表現するために使われます。

以上のことから指数の表現で使えるのは1~254の数字です。

そのため、指数部で表現できる範囲は2の(-126乗)~2の(127乗)となります。

※2の(x-127)乗という式で計算されます。xには1~254の数字が入ります。

これに対して、2の10乗(1024)で約10の3乗であることを考えると、

2の(127乗)≒10の(38.1乗)

となります。

以上のことから、float型の最大値が10の38乗のオーダーになることが納得できるでしょう。

仮数部(23ビット)

仮数部で表現するのは1以上2未満の数字です。

仮数部を理解する前に、どのように小数点のある数字を扱っているか説明します。

例えば、10進法で、0.00135という数字があった時に、

1.35×10^(-3)

と表現するでしょう。(このように表現することを正規化という)

これと同じことを2進数でも行われています。

2進数で例えば。0.0100101という数字があった時、内部では、

1.00101×2^(-2)

と表現されています。

この「1.00101」の部分が仮数部に相当し、2^(-2)が指数部に相当します。

このような説明をすると、仮数の部分に「100101…」(…は0が続く)が入っているかと思われるかもしれません。

しかし、この説明は不完全です。

2進数において、数字の大きさに合わせて小数点を動かすと、必ず、最初の一桁目(整数部)は1になります。

0になる心配がないのであれば、最初から表現しない方が得だろうということで表現されません。(精度という観点で1ビット分得をします)

※このような表現をケチ表現と言います

上の例では、「100101…」でなく仮数には「00101…」が入ります。

※例えば、仮数部が「000…」であれば、1になります。(1.000…=1)
一方「111…」であれば、仮数部で表現される数字は、2に限りなく近い数字になります。
(1.111…≒2)。

ケチ表現をすることで、有効数字を1ビット分得することを踏まえると、有効数字は2進数で24桁分あります。

これを10進法に直すと、

2の(24乗)≒10の(7.2乗)

となります。

つまり、有効数字は10進法に変換して7桁となります。

考察

以上のことを踏まえるとfloat型の最大値は、指数部で2の127乗になり、仮数部で「111…」となり、限りなく2に近いときです。

逆に、最小値は、これに-の符号がかかった時です。

では、0に近い最小の数字は何でしょうか?

指数部が2の-126乗になり、仮数部で「000…」となる場合ではありません。(つまり、1×2^(-126乗)ではないということです。)

指数部に0~255の内の0が入り、非正規化数を扱うときに最小の数字を取ります。

指数部が0の時、以下のように数字が扱われます。

(x.xxx…) ×2^(-127乗)

※(x.xxx…)には仮数部の数字が入ります。

今までの場合と大きく異なる点として、ケチ表現ができないことです。

つまり、float型で扱える指数の範囲を超えてしまったため、最初の1桁目に暗黙的に1と置くことができなくなります。

言い換えれば、小数点の位置を動かして、正規化することができなくなります。

この領域で扱える最大の数は、

「1.111…」×2^(-127乗)

です。

つまり、2^(-126乗)に近いが、2^(-126乗)と比べてわずかに小さな数となります。

一方で、最小の数は、

「0.000…1」×2^(-127乗)

です。

「0.000…1」は2^(-22乗)に相当するので、結論としては、2^(-149乗)となります。

有効数字という観点で、この領域を考えますと、2^(-127乗)のオーダーの領域から2^(-149乗)の領域に向かうにつれて、精度が悪くなることがわかります。

例えば、2^(-149乗)の手前の2^(-148乗)の領域では、以下の2つの数字しかありません。

「0.000…10」×2^(-127乗)と「0.000…11」×2^(-127乗)

つまり、1.0×2^(-148乗)と1.1×2^(-148乗)

※1.0 と1.1は2進数です。

この場合、有効数字は2進数で2桁しかありません。

10進法に変換した場合、有効数字が2桁より小さくなることがわかります。

ソースコードで確認

言語はC#でfloat型の最小値・最大値などを確認しています。

double型を使用して、上の考え方が妥当かどうか計算して確かめています。

※double型はfloat型の約2倍の精度があるとはいえ、同じような仕組みで成り立っています。そのため、float型の正しさをdouble型で確かめるという行為は、かなり怪しい部分を含んでいます。

実行結果は、

float型の最大値は3.402823E+38
float型の最小値は-3.402823E+38
float型のゼロに近い最小の数は1.401298E-45
2の127乗は1.70141183460469E+38
仮数部が1番2に近くなるのは1.99999988079071
float型の最大値を計算すると3.40282346638529E+38
float型のゼロに近い最小の数を計算すると1.40129846432482E-45

関連記事

Unityコースやアプリコースあり。無料体験の申込みあり。
  • このエントリーをはてなブックマークに追加

スポンサーリンク

コメントを残す

*

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)