★★★ Access2000VBA・Excel2000VBA独学~初心者の方や独学者の方へ:「パソコンは普通に小数計算をミスする」ということの重要性。そしてそんな大事なことを「最初に」教えてもらえない事(ひどさ)の重要性。~
※まだ書きかけです。すみません。
※間違ってたらすみません。
※メモ書きなので、自分でも意味不明な箇所も多いです。ごめんなさい。
コンピュータは、基本(もともと)、「少数」が苦手みたいで、「小数点第1位の数値が混ざった計算」といった「簡単そうに見える計算」であっても、場合によっては「平気で」「あたりまえのように」、計算間違いを起こします。
それくらい「バカで信用できない」機械です。パソコンは。
でも困ったことに、それが「正常」な状態なのです。
そして、Excelでは、その計算ミスを、自動的に正したり・正さなかったりするみたいです。(それがまためんどくさいです。)
参考URL
『 Excel で実数を扱うときの注意 セルの謎 』
(全バージョンで。ただし、当方では未確認です。2010と2000には当てはまることが確認できました。)
『 Excel VBA プログラミング 「自動型変換」に関する落とし穴 』
(全バージョンで。ただし、当方では未確認です。2010と2000には当てはまることが確認できました。)
『 Excel VBA プログラミング 実数を扱うときの落とし穴 』
(2010では起こらず、2000では起こることが確認できました。おそらく2003か2007までは起こり、2007か2010以降は起こらないのではないかと推測しています。)
まず、「Excelは自動的に正したりする」というのは、主に「セル」で行われるようです。(バージョンによっても挙動が違うようです。あ~めんどくさい。上記URLを参照してください。)
でも、一方、「正されなかったりする」のは、「VBAプログラム内」や「ユーザーフォームのテキストボックス」で起こることが少なくありません。
ということは、これは、「セルの挙動に騙されて、VBA側ではバグを生む(そしてそれはバージョンによって異なる)」という可能性を示唆しています。
上記URLのWebページにも・・・
『このように、Excel でセルが絡んだ実数計算をする場合、
ミステリアスな現象が起こるので、
実数を扱う場合には、他の言語とは異なる注意が必要です。』
・・・「他の言語とは異なる注意が必要」と書いてあります。
実際、このURLの内容を、ひとつひとつ、ゆっくりと実行していくと、驚くべきことが体験できます。
ですので、私たちユーザーは、「コンピュータで小数計算をするとき、特にExcelのセルを使って小数計算をするとき」は、Excelのバージョンの違いによって(小数点第1位での)集計結果や演算結果が異なるシーン・ケースがある「かもしれない!」、ということを常に念頭に置いておかねばなりません。
でないと、思いもよらぬバグを生み、それが、プログラムを書いた「あなたの重大な責任」になって、最悪「降格」や「減給」もありえるので、この記事のことは『VBAで計算・集計する場合の前提』として必ず覚えておいてください。
「大袈裟」「心配しすぎ」と思うかもしれませんが、ありえない話ではありませんので、どうか一度はお目をお通しください。
これはExcelだけでなく、AccessでもWordでも全部同じです。
ちなみにですが、ExcelのユーザーフォームやAccessフォームのテキストボックス(ともに非連結状態)に入力された数字は、Variant型の変数に代入すると「数字なのにもかかわらず」「数値」「ではなく」「文字列型(String型)」として扱われます。また、少数もSingle型で処理すると、計算ミスを起こします。
よって、「少数計算」でバグが出たら、ユーザーフォームやAccessフォームのせい、Excelの「セルの騙し」のせい、パソコンのせい、誤ったデータ型を指定したせい、の場合もあるのでそこから見直します。
※もちろん、人間も勘違いや忘却をするわけですから、「おバカ」です。
でも、コンピュータも「同じくらいおバカ」だということです。
「コンピュータは正確でまちがえない。」・・・そんなこと幻想です。
そんな完全な機械じゃありません。コンピュータは。
特にパソコンは。基本、「不良品」ですから・・・。人が死なないだけで。
パソコンは「完全に何かを記憶・計算できるわけじゃない」ということを必ず、忘れないでください。
もちろん「コンピュータは間違えない」という「思い込み・決めつけ」も捨ててください。
マイクロソフト社が「仕様の変更」と称してバグまがいの動きをさせることもありますし。(特に以前できたことをできなくする・できなかったことをできるようにする、などの意味で。)
その意味で、「コンピュータは間違える」、のです。
そして「それが正常」なのです。
それを忘れないでください。
「いい迷惑」、ですけど・・・。
でも言われてみれば、たとえば「1÷3」なんて「0.3333333333・・・・」と永遠に続いてしまうわけですので、それはどうしようもないですよね。
コンピュータは人間と同様、そういう計算にも弱いし、また、「1900×0.7」のような簡単な小数計算でも、プログラムの書き方(変数の型指定とか)を間違うと「1329.99997735023 」という驚くべき答えをはじき返してきます。
なので、Variant型の変数にしても似たような不具合(?不都合?)があり、そういうところをしっかりと事前に学んでおく必要があります。(Variant型を使うとセル利用の場合は少数の計算間違いは減りますが、ユーザーフォーム利用の場合は別の新たな不具合が出ますので、その意味でも、「Variant型の変数の挙動」も学んでおく必要があります。
-----------
以降では、そのような小数点の計算のお話とかをさせて頂こうかと思います。
あわせて、「変数なんか全部Variant型でいい・型の指定なんかいらない・変数の型指定でハードルが上がるならそんな型の指定などまったく必要ない」というようなことを言っている講師の方がたにも、少し、クギを刺せたらなあ、と思います。
では、まずは以下のコードをExcelでもWordでもAccesssでもなんでもいいので、標準モジュールにコピペして、ローカルウィンドウも表示してから、実行してみてください。
途中、「Stop」のところで止まるので、ローカルウィンドウにて、配列「x」の各要素の値を、「+」マークを押して展開して確認し、確認できたら「F5」キーを押して、さらに進めてください。(F8キーを押してのステップ実行でもOKです。)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
' ' Sub check04() Dim x(9) As Single Dim y As Variant Dim i As Integer Dim j As Integer '配列の各要素の10個すべてに、「0.1」を代入 For i = 0 To 9 x(i) = 0.1 Next i 'ここで「Stop」にて一旦停止して、ローカルウィンドウにて、 '配列「x」の各要素の値を、「+」マークを押して展開して確認します。 'ちゃんと全部「0.1」になっているはずです。 Stop '確認できたら、 'F5キーを押して、さらに以下のコードを実行します。 '8回目、9回目のループで、コンピュータが計算ミスを犯し、 '合計が小数点第一位ではなくなります。 'そして10回目で「たまたま」帳尻があってしまっています。 For j = 0 To 9 y = y + x(j) Debug.Print j + 1 & "回目のループの合計値・答え:" & y Next j End Sub ' ' |
このプログラムは、ループ処理(繰り返し処理)にて、『「0.1」ずつを、10回足す 』、というだけのプログラムです。
結果はこうなります。
1回目のループの合計値・答え:0.1
2回目のループの合計値・答え:0.2
3回目のループの合計値・答え:0.3
4回目のループの合計値・答え:0.4
5回目のループの合計値・答え:0.5
6回目のループの合計値・答え:0.6
7回目のループの合計値・答え:0.7
8回目のループの合計値・答え:0.8000001
9回目のループの合計値・答え:0.9000001
10回目のループの合計値・答え:1
おかしいですよね。
ローカルウィンドウで確認した、配列「x」のすべての要素の値は、すべて、ちゃんと「0.1」だったと思います。(下図)
なら、どのループの合計値も「小数点第1位」で終わらないといけません。
8回目のループの合計値・答え:0.8
9回目のループの合計値・答え:0.9
と、表示されなければおかしいです。
なのに、合計値が、「0.8000001」とか「0.9000001」って何?
そんでもって、なんで、10回目で「1」「ちょうど」になっちゃってんの?
そう思いませんか?
そのほか、「Stop」してからあとを、「F8キー」の繰り返しの押下にてステップ実行し、8回目のループが終わった直後のところで(つまり、「0.8000001」と表示された段階で)また一時停止させて、イミディエイトウィンドウにて以下のように書いてEnterすると・・・、
? y = 0.8
答えは「False」(偽=ちがうよ! 変数 y の値は 0.8 じゃないよ!)と表示されます。
これ、ほんと、おかしいですよね?
でも、これはコンピュータやVBAとしてはこの動きは「正常」なんです。
計算ミスが「正常」って、怖くありませんか?
もし、このような計算ミスの「結果」を、「何らかの条件分岐の ” 基準値 ” 」として使ってしまったらどうなるでしょう?
例えばTure/Falseなどで条件分岐の判断をしていたら、正反対の動きになってしまいますよね?
でも、それが「正常」で、「狂って当然・それが正しい」のが「コンピュータ・パソコン・Excel・Word・Access」なんです。
もう一度おたずねします。
計算ミスが「正常」って、怖くありませんか?
もちろん、これを防ぐ手立ては一応はあります。
でも、「コンピュータは小数第1位の計算すらまともにできないおばかさん」だってことももちろんですが、それよりも、もっと怖いのは、「このことを、「最初に」「注意事項として」「コンピュータでの集計・計算の ” 前提 ”として」、「ExcelVBAの講師からは」、「ひとっ言も」「教えてもらえない・説明がない」・・・、ということです。
そのことこそが、「一番怖い」・・・と、そう思いませんか?
「だからいつ何時も、少数計算するときはちょっと注意してね」とか、「変数はなるべくちゃんと型を明確に宣言してね。特にユーザーフォームは ” バカ ” だから絶対に!!」などと「ひとっ言も」「教えてもらえない」んです・・・。
怖くありませんか?
Excelって「表計算」のソフトですよね? Wordと違いますよね?
また、コンピュータが「そんなにおバカさんなんだったら」、
講師たちから「まだ教えてもらってない・隠してる」「自分が気づいていない」コンピュータの不具合は、「これだけじゃ収まらないのでは?」とか、
コンピュータに対しては、
・「信用できない!(特に小数計算)」
・「勝手に仕様変更するんじゃないだろうか?(特にセル。マイクロソフト社。)」
・「大袈裟だとしても、できるだけ、明示的に変数の宣言をしたり、ちゃんと考えてプログラミングしないとあとでとんでもないことに巻き込まれるかも? 」
・「これだけ覚えておけばOK!なんてありえない!ぜえったいに騙される!」
・「大袈裟かもしれないけど、用心するに越したことはないかも・・・講師の人が責任取ってくれるわけじゃないし(とれるはずもないし)・・・もしなんかあっても、どうせ「自己責任」って言われるだけだし・・・。」
とも思いませんか?
なんとなくでもそう、想像がつきませんか?
ぶっちゃけ「全部Variant型でいい・型の宣言なんて要らない」ってことよりも、「もし現実にあなたがバグを生み、なんらかの責追及任・処分が降りかかっても、「テキトーに教えた講師のひとたち」が責任取ってくれるわけじゃないし(とれるはずもないし)・・・もしなんかあっても、どうせ「自己責任」って言われるだけだし・・・。」ということが一番恐ろしいのです。
以下は、先ほどのプログラムに詳しいコメントが付いたコードです。
記事内容を書き換えるまで、どうぞ、ぜひ、コメントも読んでみてください。
Accessで僕が実際に遭遇した小数計算ミストラブルについても書いてあります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
' ' Sub check03() Dim x(9) As Single Dim y As Variant Dim i As Integer Dim j As Integer '配列の各要素の10個すべてに、「0.1」を代入 For i = 0 To 9 x(i) = 0.1 Next i 'ここで「Stop」にて一旦停止して、ローカルウィンドウにて、 '配列「x」の各要素の値を、「+」マークを押して展開して確認します。 'ちゃんと全部「0.1」になっているはずです。 Stop '確認できたら、 'F5キーを押して、以下のコードを実行します。 '8回目、9回目のループで、コンピュータが計算ミスを犯し、 '合計が小数点第一位ではなくなります。 'そして10回目で「たまたま」帳尻があってしまっています。 'ローカルウィンドウでのチェックでは、すべての要素の値が '「0.1」になっていたのにおかしいですね。 For j = 0 To 9 y = y + x(j) Debug.Print j + 1 & "回目のループの合計値・答え:" & y Next j 'なぜ、ローカルウィンドウで調べた結果と異なるのかわかりませんが、 'まあ、それは置いておくとして・・・ 'でもこれは困ったことに、 '「コンピュータとしては 正常・当然の動き」なのです。 '(VBAだけかもしれませんが。) 'ということは、例えばですが、 'もし、8回目の結果や9回目のような誤った「答え」を、 '「たまたま」何らかの「条件分岐の基準値」に使ってしまうと、 '反対の動き・意図しない動きになってしまうということです。 '例えばこれはExcelだけの話ではありません。 '例えば、Accessなどで、小売店が 'バーゲン価格を出すときなどにも計算間違いを起こします。 '例えば 「3割引き」、の価格を出したいために、 '「1,900×0.7」という計算をよくします。 '人間が普通に計算すれば、答えは「1,330」です。 'でも、このとき、 '「1,900」をLong型 '「0.7」をSingle型 'として計算すると、コンピュータは(VBAだけかもしれませんが)、 '驚くべきことに '「1329.99997735023 」という計算結果をはじき出していまいます。 'これは・・・、 '★ そもそも小数点が第1位よりも細かくなってしまう。ありえないはずなのに。 '★ 小数点以下を切り捨てても「1円」計算ミスしてしまう。 '・・・という2重のミスを犯してしまうことになってしまいます。 'でも、考えてみてください。 '「1,900」をLong型で宣言する、ということに関しては、 '一般的に商品の価格は「32,767」円を上回ることが多いので '「Long」型を使うことは至極自然です。 '「集計」することを考えたらなおさらそうです。 'そして、「0.7」をSingle型とすることも、 'このような計算ミスが起こるのが「普通」だなんて、 'そんなの、最初に「教わらなければ」、 '「わかるわけない・気付くわけない」、んですから、 'なんの疑いもなく「小数点第一位だからSingle型でいいだろう」 'とすることは、これも至極自然なことです。 '(※税額やバーゲン価格では「Int関数」などで切り捨てることが多いので。) '果たして、「初心者の方」で、このような結果を '「あらかじめ予測できた人」が存在するでしょうか? 'また、予測できたとしても '「どれとどれを掛け合わせたら、同じ結果になってしまうのか」 'ということを、調べて、一つ一つ対処するなんて '「可能なこと」だと思いますか? 'このような場合は、「Single」型で宣言した変数を '「Double型」にすれば、一応、全部、正しい結果が得られるようです。 'でもそれも、「たまたま」に過ぎないかもしれません。 'そして、さらに悪いことに、 'ExcelVBAの多くの講師の方たちは、 'この、「コンピュータはおバカさんだ」「少数第1位の計算すらまともにできない」、 'しかも、Excelのセルでは、 '「そのことが見えないように勝手に丸めているっぽいので気付けない(別話)」、 '「だからのセルやデータ型の妄信も危険」、 'ということを最初に教えてくれないのです。 '「ExcelやAccessってビジネス計算に使う」んだから、 ' 少数点第1位の計算ごときでおかしなことがあったら、 '「困るに決まってる!!!!!」のにです。 'それが分かっているのに「最初に」教えてくれないのです。 '少なくとも、 '「セル上での計算と、VBA上での計算は異なることがあるので注意して」 'くらいは教えないといけないと思います。 'よって、小数点の計算には、ビジネスとしては「特別な理由がない限りは」、 'データ型に「Single」を用いてはいけません。 'これはAccessだけでなく、WordでもPowerPointでもOutlookでも同じです。 'なお、「Single型」ではなくて、「Variant型」で計算すると、 '少数は自動的に「Double型」に変換してもらえるので 'この計算ミスは無くなります。 'が、 'でも、Variant型も、それ以外にもバグを生む要素があります。 '特にユーザーフォームで。 'セルの挙動も「丸め」などが勝手に行われるのか、VBAだけでの計算結果と '異なる計算をするようです。思わぬバグを生む可能性があります。 'そししてVBAも、いつまた「仕様変更」があるかわからないし、 'Variant型も、どんな勝手な型変換に悩まされるかわかりません。 'ですので、 '「事前にエラーやバグの可能性をつぶしておく」、とか、 '「コンピュータは少数計算で初心者には思いもよらない ' 計算ミスをする可能性があるから基本的には信用できない」、とか、 '「講師さんたちが ' どんな情報を隠しているかわからなく、ドツボにハメられる」、とか、 '「ある意味、マイクロソフト社が一番信用ならないかもしれない」、とか、 'そのようなことを回避する意味からも、 'Variant型ばかりを使うプログラムは書かないようにするほうが、 'データ型は自分でしっかりと決めておく方が、 '無難・かつ・賢明だと思います。 '基本、「全部Variant型でOK!」などと言っている講師は愚かだと思います。 '少なくとも、最初から「教える気」など毛頭ないと思います。 '全部Variant型にしてしまって、あとになってマイクロソフト側の '勝手な仕様変更で、「まともに動かなくなった」なんて、 '怖くてしょうがありません。 '「会社命令」として、 '「Vriant型は全部やめて、 ' 明示的にな変数宣言に全部書き換えろ!」 'という命が下ったときも恐ろしいです。 End Sub ' ' |