• ベストアンサー

-2.18+2.11=-7.00000000000003E-02 ?

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

質問者が選んだベストアンサー

  • ベストアンサー
  • PED02744
  • ベストアンサー率40% (157/390)
回答No.3

計算機は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進でぴったりあらわされるからといって、計算機の中でちゃんとぴったりとあらわされているとは限らないということです。

swodniw
質問者

お礼

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

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (7)

noname#22650
noname#22650
回答No.8

>>しかし2を何回掛けても整数になりません。 >この部分が良くわかりませんでした。 言葉足らずでした、ごめんなさい。 2.11に2を何回掛けても整数にならない。という意味です。 2を何回掛けても整数にならないので、途中で少数部分を切り捨てて、 整数×2の?乗 という形にします。そこで誤差が出ます。 VBScriptならFormat関数の代わりに FormatNumber(a+b,2) として下さい。

swodniw
質問者

お礼

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

全文を見る
すると、全ての回答が全文表示されます。
  • PED02744
  • ベストアンサー率40% (157/390)
回答No.7

No3です。 >Windowsに付属している「電卓」ではちゃんと表示されるということは、何か特別な計算方法があると考えて良いのでしょうか? ほかの方もおっしゃっていますが、単に有効桁数が決めてあるだけだと思いますよ。 昔、Pentiumのバグで小数点以下を使った掛け算の結果がおかしくなるというものがあったので、CPUとアプリの相互関係で決まるとおもいますが。 ちなみに。 どうしても、誤差がほしくないなら、10進数の演算プログラムを作ればよいのです。 その場合は、一般的には、配列を使います。 0~9までの数値を一つの配列に入るようにして、繰り上がり繰り下がりなどを実装すれば、メモリの許す限り何桁でも演算できます。 Superπなどが有名ですね。

swodniw
質問者

お礼

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

全文を見る
すると、全ての回答が全文表示されます。
回答No.6

誤差の話は皆さんがしていますので、ちょっと話を変えて、質問者様が小数点以下何桁を望んでいるかで、処理のしようがあると思います。 例えば、#2さんの言うようなFormatを使う方法もありますし、それ以外にも丸めてしまう方法もあります。 例えば5桁欲しければint(n*100000)/100000って感じ。

swodniw
質問者

お礼

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

全文を見る
すると、全ての回答が全文表示されます。
  • neKo_deux
  • ベストアンサー率44% (5541/12319)
回答No.5

> 普通の足し算なのになぜでしょう? この場合は引き算になりますし、-0.07って数を扱う時に、0.0000000000000003程度のズレは普通問題にしません。 表示上困るのなら、No.2さんのように表示桁数を制御します。 700兆円とかの金額を扱うのに、3円ズレて困るのは銀行くらいです。 銀行では、もちろんお金の計算にVBScriptだとかを使う事は無いです。 -- > どこから出てきたのでしょう? 厳密な説明は出来なくは無いですが、こちらのIEEE 754などの前提知識が必要です。 こちらの丸め誤差とかの説明。 日経PC21 / 演算誤差の正体 - IEEE 754 浮動小数点の仕組み http://pc.nikkeibp.co.jp/pc21/special/gosa/eg4.shtml Wikipedia - 浮動小数点 http://ja.wikipedia.org/wiki/%E6%B5%AE%E5%8B%95%E5%B0%8F%E6%95%B0%E7%82%B9

swodniw
質問者

お礼

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

全文を見る
すると、全ての回答が全文表示されます。
noname#22650
noname#22650
回答No.4

#2です。誤字があったので訂正します >多少の算誤が出る 多少の誤差が出る ついでなのでもう少し解説。 たとえば2.11という少数を整数×10の?乗と表現するとします。 10を2回掛ければ整数になります。 よって 211×10の-2乗 とかけます。 コンピュータ内部は2進数なので整数×2の?乗と表現しようとします。 しかし2を何回掛けても整数になりません。 途中であきらめることになるので、誤差が生まれます。

swodniw
質問者

お礼

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

全文を見る
すると、全ての回答が全文表示されます。
noname#22650
noname#22650
回答No.2

コンピュータ内部では2進数で計算しています。10進数を2進数に変換するときに、多少の算誤が出る場合があります。興味があれば「浮動小数点」について調べてください。 Format関数で書式を設定すれば期待通りの答えになります。 Dim a As Variant Dim b As Variant a = -2.18 b = 2.11 MsgBox Format(a + b, "0.##") ’有効数字小数点以下2桁

swodniw
質問者

お礼

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

全文を見る
すると、全ての回答が全文表示されます。
  • neKo_deux
  • ベストアンサー率44% (5541/12319)
回答No.1

-7.00000000000003E-02 ↓ -7.00000000000003×10のマイナス2乗 ↓ -0.0700000000000003 ですのであっています。 コンピュータは有限のメモリで連続した数値を扱うので、常にこういう誤差を持ちます。 10÷3=3.3333333333333333 とかで切っちゃうのと同じ理由です。

swodniw
質問者

補足

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

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • エクセルでメールヘッダーを解析したい(2)

    エクセルVBAで ISO-2022-JP の16進表記  dim s1 as string  s1 = "1B24422422242424262428242A233123322333233423351B284A" という値を保持しています。 これを msgbox 関数 で  あいうえお12345 と表示するように変換したいのですが,うまくいきません。 また,UTF-8 の16進数表記  dim s2 as string  s2 = "41E383A9E382A4E38396E38381E383A3E38383E38388E3839DE382A4E383B3E38388E38397E383ACE382BCE383B3" という値を,同様に msgbox 関数 で  Aライブチャットポイントプレゼン と表示するように変換したいのですが,まったく歯が立ちません。 よろしくお願いします。

  • vba 初心者

    Dim a As Integer Dim inbox As String Dim Localpath As Variant Dim c As Range, myFadd As String Dim flag As Variant Dim MyShell As Object Dim Mysh As String Dim newHour As Variant Dim newMinute As Variant Dim newSecond As Variant Dim waitTime As Variant Localpath = ThisWorkbook.Path a = 1 inbox = InputBox("番号") Do If inbox = Empty Then Exit Sub End If If inbox = Cells(a, 1) Then MsgBox ("あります") Exit Do Else a = a + 1 ElseIf Cells(a, 1) <> inbox Then MsgBox ("ない") End If Loop Set MyShell = CreateObject("WScript.Shell") MyShell.Run ("AcroRd32.exe /n") MyShell.Run ("AcroRd32.exe /p") & Localpath & "\" & Myfile & ".pdf" newHour = Hour(Now()) newMinute = Minute(Now()) newSecond = Second(Now()) + 10 waitTime = TimeSerial(newHour, newMinute, newSecond) Application.Wait waitTime Application.SendKeys "{Enter}", True '次の使用例は、10 秒を過ぎるとメッセージを表示します。 If Application.Wait(Now + TimeValue("0:00:10")) Then MsgBox "時間が過ぎました。" End If End Sub ExcelからPDFファイルを検索して印刷したいのですが、 見よう見まねで作ってみたもののエラーが出てしまってよく分かりません。 指摘できるところご指導よろしくお願いします。

  • vba初心者

    いつもお世話様です。 A列にあらかじめデータを入れといてinboxでデータを検索してもしあったらPDFファイルを開いて印刷でもしデータがなかったらinboxに戻るかたちにしたいんですけど、do...loopの使い方が分からないのと、デバックがでてしまってどう直せばいいかわかりません。サンプルコードがあれば助かります。よろしくお願いします。 Dim a As Integer Dim inbox As String Dim Localpath As Variant Dim c As Range, myFadd As String Dim flag As Variant Dim MyShell As Object Dim Mysh As String Dim newHour As Variant Dim newMinute As Variant Dim newSecond As Variant Dim waitTime As Variant Localpath = ThisWorkbook.Path a = 1 inbox = InputBox("番号") Do If inbox = Empty Then Exit Sub End If If inbox = Cells(a, 1) Then MsgBox ("あります") Exit Do Else a = a + 1 ←ここでデバックがでてしまいます。 ElseIf Cells(a, 1) <> inbox Then MsgBox ("ない") End If Loop Set MyShell = CreateObject("WScript.Shell") MyShell.Run ("AcroRd32.exe /n") MyShell.Run ("AcroRd32.exe /p") & Localpath & "\" & Myfile & ".pdf" newHour = Hour(Now()) newMinute = Minute(Now()) newSecond = Second(Now()) + 10 waitTime = TimeSerial(newHour, newMinute, newSecond) Application.Wait waitTime Application.SendKeys "{Enter}", True '次の使用例は、10 秒を過ぎるとメッセージを表示します。 If Application.Wait(Now + TimeValue("0:00:10")) Then MsgBox "時間が過ぎました。" End If End Sub

  • -2.15 + 2.11 = -0.04 ?

    以前に「-2.18+2.11=-7.00000000000003E-02 ?」で質問させて頂きました。 その時に、浮動小数点型のため、必ず誤差があるとの回答をもらいました。 今回は、前回と同様にVBScriptにて計算をしたのですが、誤差が出ていないように見えます。 誤差が出る時と出ない時の条件のようなものがあるのでしょうか? それはどのような条件なのでしょうか? 使用したコードは以下のとおりです。 Dim a Dim b a = -2.15 b = 2.11 MsgBox (a + b) (前回は「-2.15」の部分を「-2.18」としていました。) ご存知の方がいらっしゃいましたら、よろしくお願いします。

  • linest関数に配列を渡す

    こんばんは。 回帰分析をやってくれるワークシート関数にLinestとうのがありますが、 それの引数に、配列を渡したいのですが、うまくいきません。 データ自体はRangeではなく、Variant型の配列となっているのですが、Linestを 使うときは、一旦、シートに貼り付けて、配列→Range型に変換するなどするしか 対応できませんでしょうか。 もしくは、Linestと同等な自作関数を作っても良いのですが、もともと機能として あるなら、Linestを使用したいと思ってます。 うまくいかない例^^; Sub test() Dim a(1 To 3) as Variant Dim b(1 To 3, 1 To 2) as Variant a(1) = 1 a(2) = 3 a(3) = 2 b(1, 1) = 4 b(2, 1) = 5 b(3, 1) = 6 b(1, 2) = 12 b(2, 2) = 15 b(3, 2) = 19 MsgBox WorksheetFunction.LinEst(a, b, True, True) End Sub -- エクセル2003

  • VBA 標準モジュールとフォーム

    ある標準モジュール内で生成した変数の値をフォームのコマンドボタンをクリックしたら表示されるプログラムはどうやってつくるのですか? 標準モジュール sub test() dim a as integer dim b as integer dim sum as string a=5 b=1 sum=a+b End sub フォームのコマンドボタンクリック Sub CommandButton1_Click() MsgBox sum End Sub 標準モジュールで計算した答えがフォームのコマンドボタンをクリックしたら答え6が表示されるようにしたいのですが、どうしたらできますか?

  • VBAのdictionaryでAddの使い方

    VBAでつぎのコードを実行すると、a,A1.1の後、a,A2.2と表示します。 dicには、a,A2.2の設定をしていないのになぜこうなるのでしょうか? どなたか教えてください。 Sub sample() Dim dic As Object Dim subDic As Object Set dic = CreateObject("Scripting.Dictionary") Set subDic = CreateObject("Scripting.Dictionary") subDic.Add "A1", 1 dic.Add "a", subDic subDic.Add "A2", 2 '結果表示 Dim key1 As Variant Dim key2 As Variant For Each key1 In dic.keys For Each key2 In dic(key1).keys MsgBox key1 & "," & key2 & ". " & dic(key1)(key2) Next Next End Sub

  • VB6.0での小数点の扱いについて

    現在、VB6.0を使用しており、小数点の扱いに困っています。 Sub Keisan() Dim A As String Dim B As String Dim C As String A = 1.29033 B = 1.91458 C = CStr(A + CDec((B - A) / 6) * 3) MsgBox C End Sub 上記のプログラムを実行すると、 「1.602455000000001」と表示されますが、 電卓を用いて計算すると、 「1.602454998・・・」となり、微妙に誤差が出てしまいます。 小数点を整数にして計算→元の桁数に戻す、という 処理を行うと、誤差なく求めることが出来ましたが、 「もっとスマートなコードにして」と言われてしまいまして どうしたものかと思っております。 この誤差を解決する方法は無いでしょうか?

  • Excel VBA 答えが0になってしまうのですがどうしたらなおりますか?

    こんばんはB列に上からいくつか数字が入力されているとします。 そのB列の最下行にSUM関数を入力させるマクロを作成しましたが、 なぜか計算結果が0になってしまいます。 循環になってしまっていたので反復計算にチェックをいれ、再計算させましたが思ったような答えが出ませんでした。 この計算結果が0になってしまう現象はどうやっって回避したらよいのでしょうか。合計欄をC列に変えると正常になりますが、B列に計算式を入力させると0になってしまうのは、どうしてなのでしょうか。 下記のコードが悪いのでしょうか?宜しくお願い致します。 (※通常にExcel2003を使用して、単純にセルどうしの引き算をしていても答えが0になってしまう場合があります。これも同じ循環なのかも知れませんので、回避方法を教えてください。) Sub SUM関数を入力する() Dim r As Integer '最下行 Dim m As Integer '対象列 Dim a As Variant Dim siki As Variant Worksheets(3).Activate r = Worksheets(3).Range("B65536").End(xlUp).Row + 1 Range("B" & Format(r)).Select m = 2 'R1C1方式で選択 a = "R" & 2 & "C" & 2 & ":R" & r & "C" & 2 siki = "=sum(" & a & ")" Range(Cells(r, m), Cells(r, m)).FormulaR1C1 = siki End Sub

  • 配列の参照渡しで型が一致しません。

    エクセル2003です。 いつもお世話になります。 以下のコードを実行すると「配列の型が一致しません。」というエラーが出ます。 typeNameで確認しても配列の型はvariant()で正しいと思うのですが。。。 皆様のお知恵を拝借させていただけないでしょうか。 -------------------------------------- Sub main() Dim e As Variant e = fuN() Call pRo(e)  '←ここでエラーになる。 End Sub Function fuN() As Variant Dim a(0) As Variant a(0) = "zero" fuN = a End Function Sub pRo(ByRef c() As Variant) '処理っす End Sub --------------------------------------