公式アカウントからの投稿が始まります

円周率を求めるプログラムを習い自分で入力してみました。以下のものです(質問上不要な部分もあるかもしれませんが、どこまで載せればいいのか分かりませんでしたのでほとんど載せちゃいます)

Sub CalcPi()

Const NumOfSim = 20000
   
____省略_____ 

Randomize

counter = 0

For i = 1 To NumOfSim

XRand = Rnd() * 2 - 1#
YRand = Rnd() * 2 - 1#

Worksheets("sheet1").Cells(i, 5) = XRand
Worksheets("sheet1").Cells(i, 6) = YRand

distance = (XRand ^ 2 + YRand ^ 2) ^ (0.5)

If distance <= 1# Then

counter = counter + 1

End If

Worksheets("sheet1").Cells(3, 1) = i

Next i

SimPi = counter / NumOfSim * 4
Worksheets("sheet1").Cells(1, 1) = SimPi

End Sub

このプログラムの2万回を10万回にしたらエラーメッセージが出て「オーバーフロー」となりました。

そこでお聞きしたいのですが、

(1)10万回でもエラーが出ないようにするにはどのような命令を追加すればいいのでしょうか?
(2)エラーが出るのはNumOfSimに確保されているメモリーの容量(表現が正しいか分かりません)が足りないからなんでしょうか?

なにぶんど初心者で(2)は噛んで含めるようにお願いいたします。

A 回答 (8件)

Integer型変数は16bitの箱、Long型変数は32bitの箱を用意するという考え方でよいと思いますよ。



以下はOption Explicitについてです。

Option explicitを挿入しておくと、宣言していない変数をプログラムで使用していた場合にエラーが発生します。

質問者の方は、実際にはiを宣言していたようですが、Option explicitがない場合は、宣言無しにiを使っていてもエラーが発生しません。
自動的にiはVariant型として処理されます。

宣言無しに変数を使えるのは、一見便利に見えますが、プログラムの規模が大きくなってくると厳密に変数を管理する必要が出てくるため、変数は型も明確にして宣言する必要が出てきます。
また、使用メモリを必要最小限に抑えるためにも、厳密な型宣言が必要になってきます。

No.6の方が仰っている設定をすれば、“設定後に新たに作られるモジュールには”自動的に先頭にOption Explicitが入ります。
しかし、既に生成済みのモジュール(例えばCalcPi()が含まれるモジュール)には、設定を変更しても自動的にOption Explicitが挿入されませんので、自分で入れてやる必要があります。
    • good
    • 0
この回答へのお礼

何度も回答していただきありがとうございました。非常に分かりやすくよく理解できました。お世話になりました。

お礼日時:2004/07/18 22:27

No1 hsshです


もしかして、先のアドバイスは間違っていたかもしれません
宣言しない変数はvariantなんですね
てっきりintegerだと思っていました(昔のCと勘違い)
どうやらエラー原因は、エクセルそのものの仕様にあるようです
お使いのエクセルの仕様を確認してください
たぶん、65,536行までしか使えないはずです
というわけで、エラーを出さない為には、行数制限内で表示するように工夫しましょう
どちらにせよ、皆さんのいわれるように変数宣言はしたほうが良いですよ
私も、まだまだ未熟者でした (^ ^;;
    • good
    • 0
この回答へのお礼

ご親切にありがとうございました。そうなんです、10万回やるときは行が足りずにエラーになるので、毎回結果を表示する命令を外しました。

お礼日時:2004/07/18 22:30

VBAのツール - オプションで「変数の宣言を強制する」にチェックを入れておくと自動でOption Explicitを入れてくれるので、チェックしておいた方がよいです。



参考:バグの少ないプログラム
http://www.gld.mmtr.or.jp/~kunosk/home/excel/exc …

参考URL:http://www.gld.mmtr.or.jp/~kunosk/home/excel/exc …
    • good
    • 0
この回答へのお礼

回答ありがとうございました。事前にそのように設定できるんですね。参考URLもありがとうございました。

お礼日時:2004/07/18 22:20

計算機の「1」変数の保持できる数の桁数や文字の長さには、必ず制限があります。

また配列の要素数もメモリ容量との関連で制約があります。そのことを、繰り返し計算するときはまず念頭に置かねばなりません。
そのほかに、
>「円周率を求めるプログラム」とありますが、本質問は
モンテカルロ法による、円周率計算法と言います。
質問の表題としては、そのことを明記すべきでは無いかと
思います。
学理的には、少し重要でも、円周率の求め方としてはなかなか収束が悪い方法です。
http://www.cc.toin.ac.jp/club/cl01/program/pi.html
他「モンテカルロ法 円周率」でWEB照会すると数百件出てきます。
本当の円周率の多桁計算は、アルゴリズムである○○法(マーチンの公式など)の勉強が必要です。
http://www.pluto.ai.kyutech.ac.jp/plt/matumoto/p …
それと、計算途中で上位桁から確定桁が確定すると、ディスクに書き出し、メモリ上の数字としては全部は記憶しません。そのためのアルゴリズムの勉強が必要です。
数学が得意でない方には結構難しいと思います。
こちらも円周率の計算やパイ(π)でWEB照会すれば数百件出てきますので雑学的知識を得るには困りません。
    • good
    • 0
この回答へのお礼

回答ありがとうございました。

お礼日時:2004/07/18 22:17

エラーがでる直接の原因は、



  Const NumOfSim = 20000
  ↑NumOfSimの型が宣言されていない

または、

  For i = 1 To NumOfSim
  ↑iが明確に宣言されていない

のどちらか、あるいは両方だと思います。


質問(1)の回答:

NumOfSimを100,000にしてもエラーが出ないようにするためには、

  Const NumOfSim As Long = 100000

のようにNumOfSimを明確にLong型で宣言し、

  Dim i As Long

をFor文の前に挿入すればよいと思います。


質問(2)の回答:

回答の前にまず気になるのは、明示的に型を宣言しなかった場合はVariant型(なんでもあり)とみなされ、オーバーフローは発生しないはずです。
ExcelのVBAのようですので、Excelのバージョンなどにもよるのかもしれませんね。
オーバーフローが発生している以上、NumOfSimかiがInteger型として認識されているのだと思います。

以下、質問者の方の環境では、特に型を宣言しなかった場合はInteger型とみなされると仮定しての回答です。

ExcelのVBAのヘルプによると、Integer型は、-32,768~32,767の範囲の値をとることができます。
NumOfSimがIntegerであったとしても、20,000であれば格納できますし、それを代入するiがIntegerであったとしても20,000なら代入できます。
32,767よりも大きい値である100,000を格納するためには、Long型として変数を宣言する必要があります。
Long型であれば、-2,147,483,648~2,147,483,647の範囲の値をとることができます。


変数を利用するときには、面倒でも必ず型を明確に宣言したほうが良いでしょう。
また、変数の宣言を強制するOption Explicit文も入れたほうが良いでしょう。

この回答への補足

実は必要ないと思いまして省略した部分にDim i As Integer という一文がありました。これをご指摘の通りLongにしましたらうまくいきました。すみませんでした。

ところで、Integerは32,768+32,767=65,535 Longは足して4,294,967,295でそれぞれ2の16乗と32乗となると思います。ということはIntegerはNumOfSim用に16ビットのデータを収める箱を、LongはNumOfSim用に32ビットの箱を用意してください、という命令と考えればよろしいのでしょうか?

あと最後のOption Explicit文は入れないと何か不都合が出てくるのでしょうか?

補足日時:2004/07/17 21:42
    • good
    • 0
この回答へのお礼

細かく回答していただきありがとうございました。ずっと昔にBASICをやったことがあるのですが、VBAは初めてで分からないことがまだまだ多い状況です。どうもお世話になりました。

お礼日時:2004/07/18 16:34

For I <-


Iを Long等に宣言してみてはいかがでしょうか?
    • good
    • 0
この回答へのお礼

回答どうもありがとうございました。どうも、ご指摘の通りだったようです。

お礼日時:2004/07/18 16:31

No1 hsshです。

文面を改めて読んでみて、質問者の方は、もしかして原因はわかっているのかもしれないので補足します

> 10万回でもエラーが出ないようにするにはどのような命令を追加すればいいのでしょうか?

変数宣言を入れましょう
あと、インデントもあったほうがバグが減ります
    • good
    • 0
この回答へのお礼

ありがとうございました。インデントは初めて聞きました。

お礼日時:2004/07/17 22:15

VBではなく、エクセルのVBAのようですね


プログラミングの力とは、問題解決をする力なのだが
どういう原因究明方法をとりましたか?

原因はとっても簡単な事ですよ
まず、プログラムを極限まで簡単にして、
そこから、少しづつ機能を増やしていきましょう
たとえば、なにもしないカウンタupだけとか
(ほとんど答えだけどね)
    • good
    • 0
この回答へのお礼

ありがとうございました。VBAは始めて数日で、原因究明方法も思い浮かびませんでした。

お礼日時:2004/07/17 22:11

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