雑記
小数の扱いについて
最終更新:
匿名ユーザー
-
view
さて、コンピュータでの数値の取り扱いと計算についての注意点をいくつか書いてきたわけですが。
これまでに述べてきた以外にもいくつか、注意しなくてはいけない問題があります。
C言語における変数の型として、まだ述べていないものに
[float][double]
があります。
これらは【実数型】などと呼ばれ、浮動小数点数を格納できます。
これらの不動小数点数を扱う上で注意しなくてはいけないのは、浮動小数点演算には誤差がつき物である、ということです。
不動小数点数についての詳しい説明は省きますが、
例えば、浮動小数点では「0.1」を正確に表現できません。
例えば、浮動小数点では「0.1」を正確に表現できません。
コンピュータの内部ではこれまで書いてきたように2進数で数値を表現しています。それは、たとえ浮動少数点数であろうと例外ではありません。
したがって、内部的にはbitの並びでしかないものを「浮動小数点数」として処理するために規格が存在します。
一般的な処理系であれば、この規格はIEEE754でしょう。
一般的な処理系であれば、この規格はIEEE754でしょう。
この規格においては、基数が「2」となります。したがって、2の乗数(2^n:小数を表すならnはマイナスとなる)で表現されるのです。
そして、困ったことに0.1は2の乗数で表現できないのです。
したがって、
double d; d = 1/10;
としたとき、dには0.1は入っていません(!)
浮動小数点数はその表現方法から、極端に大きな値や逆に極端に小さな値を少ないbyte数で表現できるのですが、このような誤差が混入されることを念頭に入れて使用しなくてはいけません。
例えば、グラフィックアプリのサイズ指定やゲームプログラミングでの3D座標などを扱う場合であれば、ある程度値域を絞り込めると思うので、固定小数点を使用したほうが無難だと思います。
C言語で固定小数点を使うなら、単純に桁をそろえてやればいいだけです。
例えばすべて100倍して扱うと決めてしまえば、
1 → 100 0.1→ 10
とするだけ。整数型で表すことができます。
こうすれば、浮動小数点固有の誤差は生じることがありません。
API関数などに渡す時に浮動小数点を使用しなくてはいけない時だけ、適宜内部で持っている固定小数点数から変換してやればいいでしょう。C言語は「暗黙の型変換」を行ってくれるので、この変換は特に難しくはありません。
これで、とりあえず誤差なしで小数点を扱うことができるようになりました。
しかし、まだ注意しなくてはいけない点があります。
それは、整数か有限小数しか扱えない、という点です。
それは、整数か有限小数しか扱えない、という点です。
例えば1/3などは0.3333333・・・・・と無限に続きます。
したがって、コンピュータで1/3を正確に表すことはできません(1 / 3 * 3 は1にはなりません)。
したがって、コンピュータで1/3を正確に表すことはできません(1 / 3 * 3 は1にはなりません)。
同様に、pi(円周率)や平方根なども正確に表せません。
なので、特に3Dゲームなどで座標変換に三角関数を使用しますが、当然ながら誤差が出てしまいます。
これらの誤差は、浮動小数点か固定小数点かにかかわりません。
したがって、より誤差の少ない計算結果を得ようと思うなら、できるだけ途中の計算に無駄をなくすようにしなくてはいけません。上の 1 / 3 * 3 なら、/ 3 * 3は無駄なのでなくしてしまう、といった処理が必要になります。
3Dの座標変換などであれば、右に30度か移転後左に15度回転、などという処理があるならば変換用の行列(マトリクス)生成の時に右に15度回転を一度だけ行うようにすれば、誤差が少なくなるわけです。
(※この辺は詳しく説明すると長くなってしまいますが・・・。
最初のワールド座標を保持しておいて、回転等の変換を
「今の座標からの相対変換」ではなく
「最初の座標からの絶対変換」にすれば誤差が減ると
思います)
(※この辺は詳しく説明すると長くなってしまいますが・・・。
最初のワールド座標を保持しておいて、回転等の変換を
「今の座標からの相対変換」ではなく
「最初の座標からの絶対変換」にすれば誤差が減ると
思います)
コンピュータでの数値の扱いは、非常に多くの制限事項が存在します。実際、浮動小数点演算における誤差などはプログラミングなどしなくてもEXCELでも確認できます。
小数の扱いには、特に非常に注意が必要です。