- 日時: 2010/01/14 18:34
- 名前: 花ちゃん
- ***********************************************************************************
* カテゴリー:[基本コード][][] * * キーワード:計算誤差,データ型,浮動小数点数型,正確な計算結果,2進数,2進数 * *********************************************************************************** タイトル :計算の誤差について 記 事 No :13743 投 稿 日 :2009/06/10(Wed) 22:06 元質問者 :シス ----------------------------------------------------------------------------------- Debug.Print 100.1 - 90.2 という計算をすると「9.9」のはずが「9.89999999999999」という結果になりました。 これはどうしてなのでしょうか?
正確な結果を得るにはどうしたらいいのかわかりません。 調べても上手く見つからなかったので、よかったら教えて下さい
----------------------------------------------------------------------------------- 記事No :13744 投稿日 :2009/06/10(Wed) 22:31 回答者 :花ちゃん ----------------------------------------------------------------------------------- タイトルの計算の誤差や演算 誤差等をキーワードに検索すれば見つかりますよ。
データ型と演算誤差についての注意 http://support.microsoft.com/kb/409744/ja
過去のログより http://hanatyan.sakura.ne.jp/logbbs1/wforum.cgi?mode=allread&no=3276&page=0
Debug.Print 100.1@ - 90.2@ ------------------------------------------------------------ > 型による精度の所為ということでしょうか?
と言うより、今回の場合は、2進数による演算の誤差でしょうか。 ------------------------------------------------------------
----------------------------------------------------------------------------------- 記事No :13748 投稿日 :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 進型を返す場合です。 詳細はヘルプで、/ 演算子の項を見ておいてください。
|