N次元の半径1の体積を求める c++

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
たけ

N次元の半径1の体積を求める c++

#1

投稿記事 by たけ » 5年前

初めての投稿です。よろしくお願いします。
モンテカルロ法を用いた球の体積の計算です。次元は代入する形にしています。

コード:

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
int main(){
	int i,imax=100000,m,N;
	double x[m],y,X,Y=0;
	printf("input jigen N=");
	scanf("%d",&N);	
	   for(i=0;i<imax;i++){
		  for(m=0;m<N;m++){
		  x[m]=(double)rand()/RAND_MAX;
		  X+=x[m]*x[m];
	        }
	     if(X<1){Y++;}
	      X=0;
         }
	printf("%le\n",Y*(pow(2,N)/imax));
return 0;}
大学の課題を少し発展させています。(課題は3次元の球体積を求めるというもの)
上記プログラムは、インターネットを見ながら書いたのですが、読んで理解できなかった部分を飛ばしたこともあり、コンパイルしたとき 『定数式が必要(関数 main )』とエラーが出ます。
実は私はまだ[ ]の表現を習得していません。エラーがいう定数式とは[ ]の表現を定義するための式ではないかと私は思っています。

質問
私の予測はあっていますか?あっていたら・・・
[ ]はどのように使うのか、for文を用いることで、右辺が同じ式をいくつもつくることができるということですか?
必要な定義式を交えながら[ ]の使用について正確な理解を促すように教えていただけないでしょうか。
まちがっていたら・・・
どこが違うかおしえてください。

今のエラーが消えたとして、解を得ることができるプログラムになっているでしょうか?

たいちう
記事: 418
登録日時: 9年前

Re: N次元の半径1の体積を求める c++

#2

投稿記事 by たいちう » 5年前

> int i,imax=100000,m,N;
> double x[m],y,X,Y=0;

とりあえず、「xの宣言をする時点で、mの値が判らないよ]、というエラーがあります。
あなたがコンパイラだとして、この指示でxの配列はいくつ分用意したらよいのですか?

> 今のエラーが消えたとして、解を得ることができるプログラムになっているでしょうか?

エラーが消えた後、Nが2や3の時の解を吟味してみてはどうですか?
あなたが悩むことが学習なのだと思います。
一歩ずつ進みましょう。

アバター
namari
記事: 111
登録日時: 6年前

Re: N次元の半径1の体積を求める c++

#3

投稿記事 by namari » 5年前

まずエラーが出る明らかな間違いに関して・・・、
>x[m]
ここですね。mが初期化されていないので、環境依存で滅茶苦茶な数字が入ってます。

まず、[]に関してですが、これは配列というものです。

コード:

int x[a]
と宣言したら、x[0]からx[a-1]までをそれぞれ変数として使えるようになります。
中身を見ると、xとは(x[0]のデータが入ってるアドレス+b)の中の数値を表しています。
つまり、

コード:

x[0] アドレス100番
x[1] アドレス101番
x[2] アドレス102番
x[b] アドレス100+b番
ってなところでしょうか。
まあ、配列なんかはあちこちに説明がありそうなので、検索にかけて分かりやすそうなのを探したほうが早そうです。
今回はここの宣言int x[m]のmがとんでもない数、例えば-1471532だとするとint x[-1471532]なんて宣言になってしまい、PCが理解できませんので、エラーを起こします。

この配列は特に同じような行為を何回も繰り返し行うことに向いています。
まさに今回のfor文ですね。


解決法として・・・
後から配列数を変えることもできなくもないですが、配列表現の基礎をやってない段階では早過ぎる気がします。(メモリの動的割り当てといいます)
現時点ではx[1000]とか適当な数字を入れておくぐらいでどうでしょう。(入力次元が1000を超えると計算できなくなりますが。)

★エラーコードが出たらまずその文章で検索にかけてみましょう。解決方法が見つかることがよくあります。

アバター
みけCAT
記事: 6216
登録日時: 8年前
住所: 千葉県
連絡を取る:

Re: N次元の半径1の体積を求める c++

#4

投稿記事 by みけCAT » 5年前

まずインデントを整えることをおすすめします。

コード:

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
int main(){
	int i,imax=100000,m,N;
	double x[m],y,X,Y=0;
	printf("input jigen N=");
	scanf("%d",&N); 
	for(i=0;i<imax;i++){
		for(m=0;m<N;m++){
			x[m]=(double)rand()/RAND_MAX;
			X+=x[m]*x[m];
		}
		if(X<1){Y++;}
		X=0;
	}
	printf("%le\n",Y*(pow(2,N)/imax));
	return 0;
}
モンテカルロ法では誤差になりそうですが、最初の一回(i==0のとき)にXが初期化されていません。
というか、このコードなら無理に配列を使用する必要は無いと思います。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
みけCAT
記事: 6216
登録日時: 8年前
住所: 千葉県
連絡を取る:

Re: N次元の半径1の体積を求める c++

#5

投稿記事 by みけCAT » 5年前

たけ さんが書きました:今のエラーが消えたとして、解を得ることができるプログラムになっているでしょうか?
こちらで検証したところ、3~12次元ではだいたい合っているようです。(モンテカルロ法なので誤差が出るのは仕方ないです)
理論値はここでわかります。
n次元の球の体積 - 高精度計算サイト
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

たけ

Re: N次元の半径1の体積を求める c++

#6

投稿記事 by たけ » 5年前

配列を使わないとは、どのようなプログラムになるのでしょうか?
コノ程度の手間なら
N=1,2,3,4,.......
のときを一回一回、別々に作り直せばいいということですか?

アバター
みけCAT
記事: 6216
登録日時: 8年前
住所: 千葉県
連絡を取る:

Re: N次元の半径1の体積を求める c++

#7

投稿記事 by みけCAT » 5年前

たけ さんが書きました:配列を使わないとは、どのようなプログラムになるのでしょうか?
コノ程度の手間なら
N=1,2,3,4,.......
のときを一回一回、別々に作り直せばいいということですか?
今のプログラムでは、配列xに対し、x[m]に代入→その直後でx[m]の値を使用して計算 という操作だけをしており、
ほかの場所では配列にアクセスしていません。
従って、無理に配列を使う必要はなく、素直にdouble型の変数xを用意し、x[m]の代わりにxを使用して計算すればいいです。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
みけCAT
記事: 6216
登録日時: 8年前
住所: 千葉県
連絡を取る:

Re: N次元の半径1の体積を求める c++

#8

投稿記事 by みけCAT » 5年前

たけ さんが書きました:質問
私の予測はあっていますか?あっていたら・・・
[ ]はどのように使うのか、for文を用いることで、右辺が同じ式をいくつもつくることができるということですか?
必要な定義式を交えながら[ ]の使用について正確な理解を促すように教えていただけないでしょうか。
まちがっていたら・・・
どこが違うかおしえてください。
[ ]は、C言語では主に配列を宣言するときと、配列の要素にアクセスする時に使います。
よく、ポインタ型の変数pと整数iに対し、pと*(p+i)は同じだと言われます。(これが定義式?→誰か仕様書を見てくれると嬉しいです)
C++の場合、メモリの領域を確保/解放する時にも使います。
さらに、演算子オーバーロードにより、クラスによって任意の意味を持たせることもできます。

for文は、主にパラメータを変化させながら処理を繰り返す時に使用します。また、無限ループをする時にも使います。
「右辺が同じ式」とは、例えばどのようなものですか?とくに、ここでの「右辺」は何を意味していますか?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
みけCAT
記事: 6216
登録日時: 8年前
住所: 千葉県
連絡を取る:

Re: N次元の半径1の体積を求める c++

#9

投稿記事 by みけCAT » 5年前

namari さんが書きました:中身を見ると、xとは(x[0]のデータが入ってるアドレス+b)の中の数値を表しています。
つまり、

コード:

x[0] アドレス100番
x[1] アドレス101番
x[2] アドレス102番
x[b] アドレス100+b番
ってなところでしょうか。
これは正確ではありません。xは(x[0]のデータが入ってるアドレス+sizeof(x[0])*b)の中の数値になります。
つまり、

コード:

x[0] アドレス0x8000番
x[1] アドレス0x8004番
x[2] アドレス0x8008番
x[b] アドレス0x8000+4*b番
という感じですね。(sizeof(int)==4の場合)
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

たけ

Re: N次元の半径1の体積を求める c++

#10

投稿記事 by たけ » 5年前

x[m]の代わりにxを使うと、一つの次元についてしか計算出来ないのではないのですか?
任意に選んだ次元について、たった一つのプログラムの中で配列を使わずに解をもとめることはできるのですか?

右辺が同じと言ったのは、どれも乱数を用いるために、同様の式を用いている?からです。、、

たけ

Re: N次元の半径1の体積を求める c++

#11

投稿記事 by たけ » 5年前

任意に選んだ次元というのは、私はコマンドプロンプト上で選択したいという意味です。

アバター
みけCAT
記事: 6216
登録日時: 8年前
住所: 千葉県
連絡を取る:

Re: N次元の半径1の体積を求める c++

#12

投稿記事 by みけCAT » 5年前

たけ さんが書きました:x[m]の代わりにxを使うと、一つの次元についてしか計算出来ないのではないのですか?
任意に選んだ次元について、たった一つのプログラムの中で配列を使わずに解をもとめることはできるのですか?
はい。そのようなプログラムを作ることにより、できることを証明します。

コード:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>

int main(void) {
	const int imax=100000;
	int i,m,N,Y;
	srand((unsigned int)time(NULL));
	printf("input jigen N=");
	scanf("%d",&N);
	Y=0;
	for(i=0;i<imax;i++){
		double X=0.0;
		for(m=0;m<N;m++){
			double x=(double)rand()/RAND_MAX;
			X+=x*x;
		}
		if(X<1.0)Y++;
	}
	printf("%e\n",(double)Y*(pow(2.0,N)/(double)imax));
	return 0;
}
【追記】
ごめんなさい!このプログラムでは任意に選んだ次元についての解を求めることはできません。
1次元以上INT_MAX-1次元以下の整数次元についてしか求めることができませんでした。
しかし、この範囲なら任意に選ぶことができます。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
みけCAT
記事: 6216
登録日時: 8年前
住所: 千葉県
連絡を取る:

Re: N次元の半径1の体積を求める c++

#13

投稿記事 by みけCAT » 5年前

たけ さんが書きました:x[m]の代わりにxを使うと、一つの次元についてしか計算出来ないのではないのですか?
もしもこれが正しいとすると、その「一つの次元」は1次元のみですね。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

たけ

Re: N次元の半径1の体積を求める c++

#14

投稿記事 by たけ » 5年前

1次元以上INT_MAX-1次元以下の整数次元とはN=1,2,3.......ということですか?
整数なら大丈夫という意味ですか?すいません、用語も疎くて、、、

示してくれた式をもとに作ってみました。
示してくれたプログラムの20行目と21行目の間にX=0;を挿入する必要がありますよね?
そうしたら、確からしい結果が出たのですがどうでしょうか?(N=整数の次元で)

コード:

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>

int main(){
	const int imax=100000;
	int i,m,N,Y=0;
	double x,y,X=0.0;  
	srand((unsigned int)time(NULL));
	printf("input jigen N=");
	scanf("%d",&N);
	
	   for(i=0;i<imax;i++){
		  for(m=0;m<N;m++){
		    double x=(double)rand()/RAND_MAX;
		    X+=x*x;
	      }
	        if(X<1){Y++;}
	     X=0;
            }
	printf("%le\n",Y*(pow(2,N)/imax));
	return 0;
}
あと、srand((unsigned int)time(NULL));はmのfor文を回すたびに、乱数を変化させてくれるのですよね?
伝わっているかわかりませんが、つまりこれは、いつ乱数を変化させてくれているのかがはっきりわからないです。
教科書にも、起動するたびに変化する?とか、、、、まとめたものしか載っていなくていまいち腑に落ちないです。
srand((unsigned int)time(NULL));この中の文字の一つ一つの意味を説明していただけるとありがたいです。
お手数おかけします。

たけ

Re: N次元の半径1の体積を求める c++

#15

投稿記事 by たけ » 5年前

srand(........の形は丸覚えで構わないですか?
これは、毎実行時に異なる乱数を使うことができるというものですね。
調べれば分かること聞いて申し訳ないです。

上に載せた私のプログラムで問題ないですか?
一応、10次元まで求める必要があって、おそらく大丈夫だとは思うのですが、、、

アバター
みけCAT
記事: 6216
登録日時: 8年前
住所: 千葉県
連絡を取る:

Re: N次元の半径1の体積を求める c++

#16

投稿記事 by みけCAT » 5年前

たけ さんが書きました:1次元以上INT_MAX-1次元以下の整数次元とはN=1,2,3.......ということですか?
整数なら大丈夫という意味ですか?すいません、用語も疎くて、、、
「整数なら大丈夫」は間違いです。なぜなら-65537も1000000000000000000も整数であり、これらの値は使えないからです。
Nとして1以上INT_MAX-1以下の数を入力できます。int型のサイズが4バイト、charのサイズが8ビットの環境では
INT_MAX-1==2147483646のことが多いと考えられます。
ただ、Nが100000を超えてくると(imaxを変えなければ)実行に長時間かかるようになるので、実用上問題ないと思います。
たけ さんが書きました:示してくれたプログラムの20行目と21行目の間にX=0;を挿入する必要がありますよね?
「示してくれたプログラム」とはどれのことですか?
自分が提示したNo.12のプログラムには必要ないはずです。
たけ さんが書きました:あと、srand((unsigned int)time(NULL));はmのfor文を回すたびに、乱数を変化させてくれるのですよね?
違います。
乱数を取得する関数は、一般にはある呼び出しとその次の呼び出しで同じ値が返らない
(もちろんたまたま同じ値のこともあるかもしれないが)ので、「乱数を変化させる」の意味がよくわからないです。
srand関数は、それを呼び出した時点で、そのあとに呼び出されるrand関数が発生させる乱数の系列を指定します。
たけ さんが書きました:srand((unsigned int)time(NULL));この中の文字の一つ一つの意味を説明していただけるとありがたいです。
一文字ごとの説明はめんどくさい上に意味がないと思うので、一トークンごとの説明で失礼します。

コード:

srand           C言語標準ライブラリのsrand関数のアドレスが得られる識別子
(               直前で指定した関数(ここではsrand)を呼び出す演算子
  (             キャストの演算子
    unsigned    符号なしの型を示す予約語
    int         short型以上long型以下のサイズの整数型を示す予約語
  )             キャストの演算子
  time          C言語標準ライブラリのtime関数のアドレスが得られる識別子
  (             直前で指定した関数(ここではtime)を呼び出す演算子
  NULL          「どこも指していない」ポインタ。よく((void*)0)と表される
  )             直前で指定した関数(ここではtime)を呼び出す演算子
)               直前で指定した関数(ここではsrand)を呼び出す演算子
;               C言語における文の区切りを表す記号
※今のところ仕様書を持っていないため、間違っているかもしれません

ついでにもう少しまとめた説明も書いておきます。

コード:

srand(              srand関数を呼び出し、乱数系列を指定する
  (unsigned int)    次の値(ここではtime関数の戻り値 : time_t型)をunsigned int型の値に変換する
  time(             time関数を呼び出し、1970年1月1日0時0分0秒(UTC)からの経過秒数を取得する
      NULL          time関数で時刻を格納する変数のアドレスを指定する
                    ここではNULLなので、変数を指定しない→変数に時刻を格納しない
  )                 time関数を呼び出すためのカッコの終わり
)                   srand関数を呼び出すためのカッコの終わり
;                   C言語における文の区切り
たけ さんが書きました:srand(........の形は丸覚えで構わないですか?
特定の乱数系列を使用する必要がない場合(必要がある場合の例:占い、リプレイなど)は、丸覚えでいいと思います。
たけ さんが書きました:これは、毎実行時に異なる乱数を使うことができるというものですね。
だいたいあっていますが、time関数の仕様上前の実行から1秒経過する前に再び実行すると、同じ乱数になってしまうことがあります。
たけ さんが書きました:上に載せた私のプログラムで問題ないですか?
処理内容は大丈夫だと思います。
あとはインデントを整えれば、さらによくなると思います。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

たけ

Re: N次元の半径1の体積を求める c++

#17

投稿記事 by たけ » 5年前

本当にお世話になりました。
はい!あなたのプログラム間違ってません!大きなお世話でしたね。
すみません。…>_<…

本当にありがとうございました。
今後も、みかけたらご教授ください!笑
それでは

アバター
みけCAT
記事: 6216
登録日時: 8年前
住所: 千葉県
連絡を取る:

Re: N次元の半径1の体積を求める c++

#18

投稿記事 by みけCAT » 5年前

解決でしたら、解決チェックをお願いします。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

閉鎖

“C言語何でも質問掲示板” へ戻る