- ベストアンサー
マクロ変数singleで小数点計算が狂う理由とは?
- Windows8.1エクセル2010でマクロを使って小数点の計算をする際、マクロ変数singleを使用すると計算結果が正確でなくなる問題が発生します。
- 具体的には、足される数と足す数をsingle型の変数として宣言し、計算結果をsingle型の変数に代入すると、本来の計算結果と異なる値が出力されます。
- この問題を解決するためには、double型の変数を使用することで正確な計算結果を得ることができます。single型の仕組みは有効桁数が限られており、丸め誤差が生じる可能性があるため、注意が必要です。
- みんなの回答 (6)
- 専門家の回答
質問者が選んだベストアンサー
参考までに http://dobon.net/vb/dotnet/beginner/floatingpointerror.html などを読んでおくとよい。 >SingleやDoubleのような浮動小数点数型は、値を2進数で格納しています。しかし、ほとんどの10進数の小数は2進数で表現することができません。そのためこのような値はSingleやDouble型では近似値でしか表現することができず、その誤差が上記のような非常識的な計算結果として現れます。 ーー ・浮動小数点数型に変換する(言語内部で)ときの問題点(本件) ・浮動小数点数型を使いだしたら、繰り返し演算を重ねたりすると、途端にむつかしい問題に直面する。(さらに関連した問題点) ーー 参考 その他目についた記事 http://qa.atmarkit.co.jp/q/9838 http://dangerous-animal141.hatenablog.com/entry/2014/05/10/000000
その他の回答 (5)
- titokani
- ベストアンサー率19% (341/1726)
>有効桁数数は「7桁」なら、小数点第7位まで扱える…という単純なものではないのでしょうか? はい、みなさん書かれている通り、単純ではないです。 単純に使いたいのなら、Decimal型を使うのかいいと思います。 原理的にはSingle やDoubleより遅いはずですが、しょせんマクロですから、気にする程度ではないと思います。
お礼
ありがとうございました。 decimalという関数は初めてですね。 本を読みましたが、載ってない…。 HPで調べて使ってみます。
- NotFound404
- ベストアンサー率70% (288/408)
そのちゃんと出た7.2も実は怪しい。 イミディエイトウィンドウ(VBEの方で Ctrl + G)を表示し ?2.1+5.1-7.2 でEnterしてみてください。 0 になってほしいのですが、-4.44089209850063E-16 と指数表示されます。 ?2.1+5.1=7.2 では False(違う)と返ってきます。 WorkSheetでも、値が丸められて表示されるのでさらに困惑することになります。。。 ここを読んでもらうと少しスッキリするかもしれません。 第4回 演算誤差の正体 http://pc.nikkeibp.co.jp/pc21/special/gosa/eg4.shtml 1~4まであるので時間のある時にでも http://pc.nikkeibp.co.jp/pc21/special/gosa/eg4.shtml 蛇足ですが、 WorkSheet関数のRoundとVBAのRound関数の違い。 WorkSheetの方は =round(1.5,0) → 2 =round(2.5,0) → 3 これは納得できるかと思いますが、VBAのRound関数では ?round(1.5,0) → 2 ?round(2.5,0) → 2 ?round(3.5,0) → 4 銀行型丸め(偶数)になります。 他にも・・・ 興味があれば 丸めを行うカスタム プロシージャを実装する方法 https://support.microsoft.com/ja-jp/kb/196652
お礼
皆様の回答により、仕組みはわかりました。ですが、新たな疑問が沸いてしまいましたのです。 その時、頂きましたHP >第4回 演算誤差の正体 「固定小数点の方がわかりやすいですよね。どうして浮動小数点を使うんですか?」 同じ質問を、ハルがしてましたが、エリカの回答で、スッキリです。 ありがとうございました。
- chie65536(@chie65535)
- ベストアンサー率44% (8740/19838)
追記と訂正。 Windows7以降のバージョンのWindowsに付属の電卓で 4 2 1 0.125 0.0625 0.0078125 0.00390625 0.00048828125 0.000244140625 0.000030517578125 0.0000152587890625 0.0000019073486328125 0.00000095367431640625 を全部足すと、EXCELとは異なり 7.19999980926513671875 という答えを表示し 7.19999980926513 になりません。 これは「Windowsの電卓が、四則演算に限り、独自の精度で演算をしているから」で、EXCELなどの「IEEE浮動小数点数」とは異なる結果になります。
お礼
ありがとうございました。 最初は、変な小数点で ? マークがつきましたが、理由がわかって良かったです。 何度も回答頂きありがとうございました。
- chie65536(@chie65535)
- ベストアンサー率44% (8740/19838)
Singleは「単精度浮動小数点数」と言います。 Doubleは「倍精度浮動小数点数」と言います。 IEEE単精度では、データ構造は 符号1ビット+指数部8ビット+仮数部23ビット になっています。倍精度では 符号1ビット+指数部11ビット+仮数部52ビット になっています。 で、実際にどのように数値を記憶しているかと言うと「2進数で記憶」しています。 例えば「7.5」なら「2の2乗+2の1乗+2の0乗+2の-1乗」つまり「4+2+1+0.5」のように記憶しています。 では、2.1は、と言うと 2の1乗+2の-4乗+2の-5乗+2の-8乗+2の-9乗+2の-12乗+2の-13乗… つまり 2+0.0625+0.03125+0.00390625+0.001923125+0.000244140625+0.0001220703125+... のようになります。 2進数で書くと 10.0001100110011001100110011001100110011001100110011... です。 この数値を単精度で記録すると、仮数部は23ビットしかありませんから 10.0001100110011001100110 までしか記憶できません。 5.1も同様に 101.000110011001100110011 までしか記憶できません。 この2つを足し算した値も 111.001100110011001100110 までしか記憶できません。 ここで、この「単精度の値」を「倍精度で記憶している、セルに代入する」と、どうなるでしょうか? 倍精度は「仮数部52ビット」ですから「単精度の値を倍精度に代入すると、29ビット分、足りない」ですから「余った29ビット分」には「0」が足されます。 なので、セルには、2進数で 111.00110011001100110011000000000000000000000000000000 という値が代入されます。この値は、倍精度では 7.19999980926513 という値になります。 倍精度では、7.2は、2進数で 111.00110011001100110011001100110011001100110011001100 という値になりますから 111.00110011001100110011000000000000000000000000000000 という値は「7.2より、ちょっと小さい値」になってしまいます。 試しに、電卓で 4 2 1 0.125 0.0625 0.0078125 0.00390625 0.00048828125 0.000244140625 0.000030517578125 0.0000152587890625 0.0000019073486328125 0.00000095367431640625 を足してみて下さい。「7.19999980926513」になり、7.2にはなりません。 「変な値になる理由(7.2にはならない理由)」は「単精度を倍精度に変換した時に、足りない29ビット分が、0で埋められたから」です。 このような「精度が異なる物に変換して代入した時の誤差」を防ぐには「一旦、文字列に変換してから、数値に変換する」などの工夫が必要です。 例えば ActiveCell.FormulaR1C1 = 合計 の行を ActiveCell.FormulaR1C1 = Val(Str(合計)) に変えてみて下さい。C1セルに、ちゃんと「7.2」が代入されます。
- f272
- ベストアンサー率46% (8467/18126)
7.19999980926513の8桁目(小数点以下8桁ではなく,一番大きな桁から数えて8桁目)を四捨五入するとちゃんと7.2になっているよね。有効桁数が7桁と言うのはそういうことです。
お礼
確かに、四捨五入すると 7.2ですね。 ありがとうございました。
お礼
>http://dobon.net/vb/dotnet/beginner/floatingpointerror.html とてもわかりやすいページでした。 あと、固定小数点数と浮動小数点数で、仕組みがわかりました。 ありがとおうございました。