お願いします

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

お願いします

#1

投稿記事 by 孫策 » 14年前

C言語でモンテカルロ法を使ってf(x)=exp(-0.5*x)範囲は-5から0の計算をするプログラムを作りたいのですがやっても全然うまくいかないのでご助力お願いします
ちなみに計算結果は22.365になるそうです

box
記事: 2002
登録日時: 14年前

Re: お願いします

#2

投稿記事 by box » 14年前

その、全然うまくいかない、というソースコードを見せてください。
話はそこからです。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

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

Re: お願いします

#3

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

ソースコード以前に、問題を正確に記述してください。

孫策

Re: お願いします

#4

投稿記事 by 孫策 » 14年前

返信ありがとうございます
ソースは改良しすぎたせいでぐちゃぐちゃになってしまいましたのもう少し待ってもらえますでしょうか

問題文は
モンテカルロ法を使って区間[a,b]における関数f(x) ( f(x)>0, a<=x<=b )の定積分を計算するプログラムを作成せよ
ただしここではf(x)=exp(-0.5*x)[-5,0]
また、関数f(x)はC言語として実現すること

です

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

Re: お願いします

#5

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

正しく計算できるプログラムが完成してからでないと改良はできないはずだし、
ぐちゃぐちゃになってしまったのならば改良じゃない、
というお約束のつっこみは我慢しよう。

モンテカルロ法については円周率を求めるサンプル等が簡単に見つかるだろうし、
原理を理解したら定積分に応用するのもそれほど難しくない。
というわけでプログラムを作ってみたが、何故か正しい答がでない、
という状況と思ってよいでしょうか?
だとすると、ソースコードが貼られてからしかアドバイスできません。

孫策

Re: お願いします

#6

投稿記事 by 孫策 » 14年前

>>正しく計算できるプログラムが完成してからでないと改良はできないはずだし、
ぐちゃぐちゃになってしまったのならば改良じゃない、
というお約束のつっこみは我慢しよう。

改造の間違えですねすいません


>>モンテカルロ法については円周率を求めるサンプル等が簡単に見つかるだろうし、
原理を理解したら定積分に応用するのもそれほど難しくない。
というわけでプログラムを作ってみたが、何故か正しい答がでない、
という状況と思ってよいでしょうか?

正直にな話原理はまったく理解してませんというか理解できません
勉強はしてるのですがまだそこまで追いついてない状態なので宿題をやるのが精一杯な現状がいまです
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#define F(x) exp(-0.5*x)

float frand()
{
return rand()/(RAND_MAX+1.0);
}

main()
{
int k, m, n;
float a, b, c, x, y, s;
a=-5;
b=0;
printf("[m]");
scanf("%d", &m);
printf("[c]");
scanf("%f", &c);
k=n=0;
srand((unsigned)time(NULL));
while(++n <m){
x= frand();
y= frand();
if(y<F(x)) k++;
}

s= F(b)-F(a);
printf("Sum = %f\n", s);
}

これが自分の今の限界です
間違いしかないかもしれませんがよろしくお願いします

non
記事: 1097
登録日時: 14年前

Re: お願いします

#7

投稿記事 by non » 14年前

モンテカルロ法について理解されてません。プログラムの前にモンテカルロ法について調べてください。
なお,このような問題を解くときは,どのようなグラフになるかを知らなくてはいけません。
参考までに,画像を添付しました。
-5のときのf(x)の値は,12.1825です。
添付ファイル
無題.jpg
non

孫策

Re: お願いします

#8

投稿記事 by 孫策 » 14年前

>>モンテカルロ法について理解されてません。プログラムの前にモンテカルロ法について調べてください。

それは↑でもいった通り理解しています
調べても理解ができませんので

>>なお,このような問題を解くときは,どのようなグラフになるかを知らなくてはいけません。
参考までに,画像を添付しました。
-5のときのf(x)の値は,12.1825です。

一応グラフの形もその値になることもわかっています

non
記事: 1097
登録日時: 14年前

Re: お願いします

#9

投稿記事 by non » 14年前

>調べても理解ができませんので

そうですか、失礼しました。
xの範囲は当然、-5から0の範囲で乱数を発生させますよね。yの範囲は、孫策さんは、いくらで発生させたいですか?
これは、孫策さんが決めることです。
すると、その範囲の面積はいくらになりますか?
次に、乱数は何回発生させますか?仮に100000回としたら、if(y<F(x)) k++;でカウントした回数との比から、面積が出ますね。

なお、プログラムではfloatより、doubleで計算させましょう。
non

孫策

Re: お願いします

#10

投稿記事 by 孫策 » 14年前

[quote="non"]>調べても理解ができませんので

>>そうですか、失礼しました。
情けなくてすいません

ネットで調べて参考にさせてもらい新たに#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#define F(x) (exp(-0.5*x))

double frand()
{
return rand()/(RAND_MAX);
}

void syuku(int i)
{
int k, n;
double a, b, y, x, sum;
a=-5;
b=0;
k = i;
n = 0;
srand((unsigned)time(NULL));
while(k>0){
--k;
x=frand()*b;
y=frand();
if(F(x)>=y) n++;
}
sum = (F(b)-F(a))*(double)n/i;
printf("Sum = %f\n", sum);
}

main()
{
return 0;
}

を書いてみたんですがやはりできませんでした

やっぱりyの範囲とかが重要なのでしょうか?

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

Re: お願いします

#11

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

> やっぱりyの範囲とかが重要なのでしょうか?

理解しないで正しいプログラムが書けるわけがありません。
何を調べ、何が判らないのかを書けば、アドバイスできるかも。

孫策

Re: お願いします

#12

投稿記事 by 孫策 » 14年前

>>理解しないで正しいプログラムが書けるわけがありません。
いつも理解せず時間をかけて作ってます…

>>何を調べ、何が判らないのかを書けば、アドバイスできるかも。
とりあえずモンテカルロ法の積分で類似問題っぽいものを調べて
そこをいじって今に至る訳なんですが
理解してないから解らないもの具体的にいうのは難しいのですが
どこから狂っているのか指摘していただきたいです

non
記事: 1097
登録日時: 14年前

Re: お願いします

#13

投稿記事 by non » 14年前

プログラムの態をなしていません。
モンテカルロ法云々という以前の問題かもしれません。

ある範囲の点をi回発生させ、その点がf(x)の上にあるか下にあるかで、カウントします。仮に、f(x)の下に点が打たれた回数を
n回とすると、n/iが割合になります。ある範囲の面積をsとするなら、求める積分の面積はs*k/nで求められます。
>sum = (F(b)-F(a))*(double)n/i;
この式がそのつもりですね。(F(b)-F(a))は面積ではないですね。高さです。でも、b=0、a=-5なら、F(b)-F(a)<0になっちゃうでしょ。
だから、グラフを見るように伝えてます。ここまで、理解できますか?
non

孫策

Re: お願いします

#14

投稿記事 by 孫策 » 14年前

おっしゃっている意味合いはだいたいわかります

孫策

Re: お願いします

#15

投稿記事 by 孫策 » 14年前

逸れてすいませんがこのプログラムで実行したら値が不安定ですがだいたい22.~って感じになったのですが小数点以下を安定させるためにはやはり改良が必要でしょうか?

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#define F(x) (exp(-0.5*x))

double f(double x){
return x;
}

int main(){
int n, m, k;
double a, b, c, x, y, s;
m=100000;
a=-5;
b=0;
c=13;
k=n=0;
srand((unsigned)time(NULL));
while(++n < m){
x= a+(b-a)*(double)rand()/RAND_MAX;
y= c*(double)rand()/RAND_MAX;
if(y<F(x)) k++;
}
s=(double)k/n*c*(b-a);
printf("Sum = %f\n", s);
return 0;
}

初級者
記事: 200
登録日時: 14年前

Re: お願いします

#16

投稿記事 by 初級者 » 14年前

結果の値を安定させることはできません。
試行回数を多くすることで精度を上げることはできます。

乱数を使う、というモンテカルロ法の性質上、
毎回結果が異なって当たり前です。

コード:

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

#define WIDTH  (5)
#define HEIGHT (13)

int main(void)
{
    int n, i, count;

    srand((unsigned int) time(NULL));
    do {
        printf("試行回数:");
        scanf("%d", &n);
    } while (n <= 0);

    for (count = i = 0; i < n; i++) {
        double x = (double) rand() / RAND_MAX * -WIDTH;
        if ((double) rand() / RAND_MAX * HEIGHT <= exp(-0.5 * x)) {
            count++;
        }
    }

    printf("%f\n", (double) count / n * WIDTH * HEIGHT);
    return 0;
}

non
記事: 1097
登録日時: 14年前

Re: お願いします

#17

投稿記事 by non » 14年前

OKです。答えが異なるのは、初級者さんが言われる通りです。

細かいところですが、

>double f(double x){
>return x;
>}

これは、何かの残骸ですね。不要です。

>while(++n < m){
これでは、ループ回数がm-1です。1回少ない。

>rand()/RAND_MAX
これですと、乱数範囲は 0<= x <=1
で、両方に=が付きます。それが、わかって使ったのなら、これでかまいません。
一般的には
rand()/(RAND_MAX+1)


>c=13;
高さを13に固定してしまったのは、概算値としてはかまいません。しかし、精度をあげるなら、
F(-5)-F(0)の範囲で乱数を発生させた方がいいでしょう。
non

孫策

Re: お願いします

#18

投稿記事 by 孫策 » 14年前

>>これは、何かの残骸ですね。不要です。

除き忘れました、ありがとうございます

>これでは、ループ回数がm-1です。1回少ない。

改善してみます


>これですと、乱数範囲は 0<= x <=1
で、両方に=が付きます。それが、わかって使ったのなら、これでかまいません。
一般的には
rand()/(RAND_MAX+1)

今回は一応解ってましたが次回からは下でいこうと思います


>高さを13に固定してしまったのは、概算値としてはかまいません。しかし、精度をあげるなら、
F(-5)-F(0)の範囲で乱数を発生させた方がいいでしょう。

解りました。改善させてみます

長い時間本当にありがとうございました

初心者さんもありがとうございます
参考になりました

閉鎖

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