夢をありがとう!さようならMac(ToT)forevr
この計算結果が0とならないのは、計算機で実数演算を行う際の基本的な
問題によっています。すべての原因は10進数を有限桁の2進数で表わす事に
あります。実際のExcelの内部表現形式とは違いますが、例えば仮数部12桁
として扱っていると考えると、この計算誤差の発生メカニズムは以下のよう
になります(仮数部の大きさは0.5〜1とします)。
まず1.1と1.0を仮数部12桁の浮動小数点形式で書いてみます。
二進数表現
十進数表現 仮数部 指数部
1.1 0.100011001100 2 1.1は2進数表記では循環
1.0 0.100000000000 2 小数となります。
では1.1から1.0を引いてみましょう。
1.1-1.0 0.000011001100 2 これは0.1です。仮数部を
1.1-1.0 0.000110011000 1 ルールに合わせて直します。
式の最後の0.1は二進数表現で次のようになります。
0.1 0.000110011001 1 0.1も循環小数になります。
ということで式を最後まで計算します。
1.1-1.0-0.1 -0.000000000001 1
Excelの実際の計算結果とは異なりますが、ご覧のように見事に誤差が出
てきます。このように、絶対値が同じくらいの数同士の引算による誤差を桁
落ちの誤差といいます。
10進数を2進数で表わさなくてはならない計算機では不可避の誤差で、数
値計算を行う際には留意しなくてはならない事の一つです。
ところで、CP/M上のSuperCalcでは同じ計算を行ってもちゃんと0になりま
す。また、CASIOやSHARPのポケコンのBASICでも問題ありません(もちろん
もっと低機能な8桁のソーラー電卓でも)。これらは二進化十進数(Binary
Coded Decimal, BCD)という表現形式を用いて、10進数での表示桁分はその
とおりの値として扱う(つまり0.1はきちんと0.1となる)ようになっている
ためです。おそらくCOBOLもBCD演算を行っていると思います。
BCD演算は通常の浮動小数点表現に比べて同じ大きさの数を保持するため
により多くの記憶領域が必要であり、計算も遅いというデメリットがありま
す。昔のコンパイラにはBCD形式をサポートしたものも結構あったようで、
演算精度と演算速度/メモリ消費を秤にかけて使い分けていたようです。現
在の表計算ソフトでBCDを用いていないのは、倍精度演算が当り前となり二
進数―十進数の変換に起因する誤差が小さくなって来ているためではないか
と思います。何と言ってもSuperCalcは単精度でしか計算出来ないため、BCD
で計算しない事には誤差が累積して大変な事になってしまいます。
とは言え、10E-15オーダーの誤差とは言え、数値計算に関する知識がない
人にとっては誤った結果が出ている事には違いありません。この問題をソフ
トメーカーが何とかしようと思っているかはかなり疑問に思えますので、こ
うした知識はコンピュータリテラシーの一部として教育していかなくてはな
らないのかなあと思っています。
私の職場でも、先日Excelで同じような問題で困っている人がいました。
=IF(A1+B1+C1+D1=E1-F1,"Yes","No")というような式で、A1+B1+C1+D1とE1-
F1が演算桁長の一番最後の辺りで一致せず人間が期待した通りの結果となら
ないというものでした。今と同じような説明をした上で、私ならABS(A1+B1+
C1+D1-(E1-F1))<1E-10とするだろうと同僚にはアドバイスしました(A1など
の値を考慮して不等号の右辺を決めるなど注意が必要ですが)。
n-(n-0.1)-0.1
の方程式の類は全滅だってことだね。
>>276 #include <stdio.h>
int main(void)
{
printf("%f\n", 3.0-2.1-0.9);
return 0;
}
(略)
[localhost:/Desktop] zero_bit% cc test.c
[localhost:/Desktop] zero_bit% ./a.out
-0.000000
[localhost:/Desktop] zero_bit%
---------------------------------------------------------
自分で書けば正解を出してくれるから、
「OSの根本的な問題」ということは無いのでは?
もしくはCFMアプリだと旧MacOS用のバイナリフォーマットを受け継いでいるらしいから、
CFMアプリでは計算を間違えるとか。
まぁどちらにしろMacOS10.xで問題が無いならいいや。