プロが教えるわが家の防犯対策術!

VBScriptで次の計算をすると、期待した答えになりません。
なぜでしょう?
Dim a As Variant
Dim b As Variant
a = -2.18
b = 2.11
MsgBox a + b
表示される答え:-7.00000000000003E-02
期待する答え:-0.07

原因がわからず困っています。

A 回答 (8件)

計算機は2進数で計算していることはご存知ですね?


小数点以下も同じく、2進数で計算します。
本当は、小数点以下は、IEEE形式と呼ばれるもので表現しているので、かなりちがうのですが、簡単のために一般的な2進数表記で少数以下をあらわしてみましょう。

10進数の0.1は10の-1乗ですね。
当然ですが、2進数でも同じ考え方をします。
2進数の0.1は2の-1乗です。 2の-1乗はいくらでしょう?0.5ですね。
同じく、2進数の0.01は2の-2乗なので0.25です。以下0.125, 0.0625,0.03125,....となります。

ここで、10進数の0.1は2進数ではいくらか考えてみましょう。
0.1=0.0625+0.03125+....となって、循環小数になってしまいます。

あなたのご質問に戻ると、このように、2進数の少数形式でいったん内部で保持されてから、計算するので、10進では起こらなかった誤差というものが生じてしまうのです。

10進でぴったりあらわされるからといって、計算機の中でちゃんとぴったりとあらわされているとは限らないということです。
    • good
    • 0
この回答へのお礼

奥が深いんですね。
簡単な足し算なのになぜ?って思ってましたが、2進数で小数を表現するときの問題だったんですね。
Windowsに付属している「電卓」ではちゃんと表示されるということは、何か特別な計算方法があると考えて良いのでしょうか?
もしご存知でしたら教えてください。
ありがとうございました。

お礼日時:2006/11/01 13:45

>>しかし2を何回掛けても整数になりません。


>この部分が良くわかりませんでした。

言葉足らずでした、ごめんなさい。

2.11に2を何回掛けても整数にならない。という意味です。

2を何回掛けても整数にならないので、途中で少数部分を切り捨てて、
整数×2の?乗 という形にします。そこで誤差が出ます。

VBScriptならFormat関数の代わりに

FormatNumber(a+b,2)

として下さい。
    • good
    • 1
この回答へのお礼

ありがとうございます。
やはり小数には誤差があることを意識して
FormatNumber(a+b,2)
のように書いておかないといけないのですね。
今まで全く意識していませんでしたので、参考になりました。

お礼日時:2006/11/01 15:50

No3です。


>Windowsに付属している「電卓」ではちゃんと表示されるということは、何か特別な計算方法があると考えて良いのでしょうか?

ほかの方もおっしゃっていますが、単に有効桁数が決めてあるだけだと思いますよ。
昔、Pentiumのバグで小数点以下を使った掛け算の結果がおかしくなるというものがあったので、CPUとアプリの相互関係で決まるとおもいますが。

ちなみに。
どうしても、誤差がほしくないなら、10進数の演算プログラムを作ればよいのです。
その場合は、一般的には、配列を使います。
0~9までの数値を一つの配列に入るようにして、繰り上がり繰り下がりなどを実装すれば、メモリの許す限り何桁でも演算できます。
Superπなどが有名ですね。
    • good
    • 1
この回答へのお礼

ありがとうございます。
10進数の演算プログラムですか・・・
最初に配列に格納する時に、誤差が入りそうな気がします。
ちょっと大変そうですね。

Pentiumのバグの話、参考になりました。
そんな事があったとは知りませんでした。

お礼日時:2006/11/01 15:39

誤差の話は皆さんがしていますので、ちょっと話を変えて、質問者様が小数点以下何桁を望んでいるかで、処理のしようがあると思います。


例えば、#2さんの言うようなFormatを使う方法もありますし、それ以外にも丸めてしまう方法もあります。
例えば5桁欲しければint(n*100000)/100000って感じ。
    • good
    • 0
この回答へのお礼

ありがとうございます。
教えて頂いた形で次のようにやってみました。
Int(-2.18*100)/100 + Int(2.11*100)/100
でも結果は期待した答えにはなりませんでした。
Fix(-2.18*100)/100 + Int(2.11*100)/100
でも試しましたが、やはり期待した答えにはなりませんでした。

お礼日時:2006/11/01 15:32

> 普通の足し算なのになぜでしょう?



この場合は引き算になりますし、-0.07って数を扱う時に、0.0000000000000003程度のズレは普通問題にしません。
表示上困るのなら、No.2さんのように表示桁数を制御します。

700兆円とかの金額を扱うのに、3円ズレて困るのは銀行くらいです。
銀行では、もちろんお金の計算にVBScriptだとかを使う事は無いです。

--
> どこから出てきたのでしょう?

厳密な説明は出来なくは無いですが、こちらのIEEE 754などの前提知識が必要です。
こちらの丸め誤差とかの説明。

日経PC21 / 演算誤差の正体 - IEEE 754 浮動小数点の仕組み
http://pc.nikkeibp.co.jp/pc21/special/gosa/eg4.s …

Wikipedia - 浮動小数点
http://ja.wikipedia.org/wiki/%E6%B5%AE%E5%8B%95% …
    • good
    • 0
この回答へのお礼

「普通問題にしません」って言われても、問題としているので質問させて頂きました。申し訳ありません。
教えて頂いたサイトは参考になりました。
まだ内容を全て理解できていないので、少しずつ進めていきたいと思います。
ありがとうございました。

お礼日時:2006/11/01 13:39

#2です。

誤字があったので訂正します
>多少の算誤が出る
多少の誤差が出る

ついでなのでもう少し解説。
たとえば2.11という少数を整数×10の?乗と表現するとします。

10を2回掛ければ整数になります。
よって 211×10の-2乗 とかけます。

コンピュータ内部は2進数なので整数×2の?乗と表現しようとします。
しかし2を何回掛けても整数になりません。
途中であきらめることになるので、誤差が生まれます。
    • good
    • 0
この回答へのお礼

>しかし2を何回掛けても整数になりません。
この部分が良くわかりませんでした。
2×1=2
2×2=4
整数になるように思いますが、私の勘違いでしょうか?
誤差が出るということは、理解したつもりです。
ありがとうございます。

お礼日時:2006/11/01 13:42

コンピュータ内部では2進数で計算しています。

10進数を2進数に変換するときに、多少の算誤が出る場合があります。興味があれば「浮動小数点」について調べてください。

Format関数で書式を設定すれば期待通りの答えになります。

Dim a As Variant
Dim b As Variant
a = -2.18
b = 2.11
MsgBox Format(a + b, "0.##") ’有効数字小数点以下2桁
    • good
    • 0
この回答へのお礼

ごめんなさい。VBScriptなのでFormat関数は使えませんでした。
でもNo4の回答をもらい、少し分かったような気がします。
ありがとうございました。

お礼日時:2006/11/01 13:52

-7.00000000000003E-02



-7.00000000000003×10のマイナス2乗

-0.0700000000000003

ですのであっています。
コンピュータは有限のメモリで連続した数値を扱うので、常にこういう誤差を持ちます。
10÷3=3.3333333333333333
とかで切っちゃうのと同じ理由です。

この回答への補足

E-02 は 10のマイナス2乗を掛ける意味ですね。
では、その前の「3」はどこから出てきたのでしょう?
Windowsに付属している「電卓」ではちゃんと「-0.07」となるのですが、VBScriptでは無理なのでしょうか?
10÷3が3.3333333333333333となるのは、「電卓」でも同じ結果なので納得できるのですが、普通の足し算なのになぜでしょう?

補足日時:2006/10/31 18:56
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!