tagCANDY CGI VBレスキュー(花ちゃん)の Visual Basic 6.0用 掲示板
VBレスキュー(花ちゃん)の Visual Basic 6.0用 掲示板
[ツリー表示へ]  [ワード検索]  [Home]

タイトル Re^5: 計算の誤差について
投稿日: 2009/06/11(Thu) 11:30
投稿者魔界の仮面弁士
> 100.1 か 90.2 かはわかりませんが、2進で表現しきれないということでしょうか?

2 進で誤差なく表せる数は、(2^X) の累積で表せる物です。
 15.75 = (1 * 2^3) + (1 * 2^2) + (1 * 2^1) + (1 * 2^0) + (1 * 2^-1) + (1 * 2^-2) → 1111.11 {2進}
 10.00 = (1 * 2^3) + (0 * 2^2) + (1 * 2^1) + (0 * 2^0) + (0 * 2^-1) + (0 * 2^-2) → 1010.00 {2進}
  9.00 = (1 * 2^3) + (0 * 2^2) + (0 * 2^1) + (1 * 2^0) + (0 * 2^-1) + (0 * 2^-2) → 1001.00 {2進}
  4.50 = (0 * 2^3) + (1 * 2^2) + (0 * 2^1) + (0 * 2^0) + (1 * 2^-1) + (0 * 2^-2) → 0100.10 {2進}
  1.25 = (0 * 2^3) + (0 * 2^2) + (0 * 2^1) + (1 * 2^0) + (0 * 2^-1) + (1 * 2^-2) → 0001.01 {2進}

10 進で誤差なく表せる数は、(10^X) の累積で表せる物です。
 999.99 = (9 * 10^2) + (9 * 10^1) + (9 * 10^0) + (9 * 10^-1) + (9 * 10^-2)
 100.10 = (1 * 10^2) + (0 * 10^1) + (0 * 10^0) + (1 * 10^-1) + (0 * 10^-2)
  90.20 = (0 * 10^2) + (9 * 10^1) + (0 * 10^0) + (2 * 10^-1) + (0 * 10^-2)
   4.50 = (0 * 10^2) + (0 * 10^1) + (4 * 10^0) + (5 * 10^-1) + (0 * 10^-2)
   1.25 = (0 * 10^2) + (0 * 10^1) + (1 * 10^0) + (2 * 10^-1) + (5 * 10^-2)


ちなみに、「10 ÷ 3 は割り切れない」というのは、10 進や 2 進の場合の話であって、
3 進であれば割り切れる数として表す事が可能です。

「10 ÷ 3」
 10 進数 → 3.3333333… [無限小数]
  3 進数 → 10.1 [ちょうど割り切れる] = (1 * 3^1) + (0 * 3^0) + (1 * 3^-1)
  2 進数 → 11.010101… [循環小数]

「1 ÷ 3」
 10 進数 → 0.333333… [無限小数]
  3 進数 → 0.1 [ちょうど割り切れる] = (1 * 3^-1)
  2 進数 → 0.010101… [循環小数]

「1 ÷ 10」
 10 進数 → 0.1 [ちょうど割り切れる]
  3 進数 → 0.00220022002… [循環小数]
  2 進数 → 0.0001100110011… [循環小数]

「1 ÷ 2」
 10 進数 → 0.5 [ちょうど割り切れる] = (5 * 10^-1)
  3 進数 → 0.111111… [無限小数]
  2 進数 → 0.1 [ちょうど割り切れる] = (1 * 2^-1)
--------------

桁数が無限にあれば、循環小数になっても正しい数値を表せますが、
コンピュータのメモリは有限です。各変数は数バイト程度の領域しかないため、
途中の桁で打ち切られ、その差が『誤差』となります。

100.1 も 90.2 も、10進では小数部は 1 桁で表せていますが、
これらの数を 2進数にすると、いずれも循環小数になってしまうのです。

そして倍精度浮動小数点型では、内部が2進で管理されています。
誤差を含んだ値同士を演算すれば、結果も誤差を含むことになるという事です。



> 通貨型ですか。
> 型による精度の所為ということでしょうか?

通貨型だと問題が出なかったのは、通貨型の内部表現が、8バイトの「整数」であるからです。

たとえば、123.45 という小数があった場合、通貨型の内部では 10,000 倍した「1234500」に相当する
整数値で保持されています。ヘルプの『通貨型 (Currency)』の項も参照しておいてください。

今回の 100.1@ - 90.2@ という演算であれば、「1001000」-「902000」=「99000」として内部処理され、
これが 9.9000 という結果として表されているのだとイメージしてみてください。

なお通貨型の場合、この「10,000 倍」の内部仕様があるために、
「小数部の桁数が 4 桁を超える値を正しく扱えない」という点を覚えておいてください。
---------

また、今回の件とは関係ありませんが、割り算を行う際にも注意してください。VB6 において
 a / b
という除算を行うと、a, b 双方が通貨型であったとしても、結果は Double となります。
殆どの場合、「/ 演算子」は、倍精度浮動小数点数型(Double)となる仕様である事を覚えておいてください。

なお、a, b の型によっては、倍精度浮動小数点数型(Double)型以外を返すパターンもあります。
単精度浮動小数点数型(Single) になる場合と 10 進型を返す場合です。
詳細はヘルプで、/ 演算子の項を見ておいてください。

- 関連一覧ツリー をクリックするとツリー全体を一括表示します)

古いスレッドにレスはつけられません。