ページ 11

乱数について

Posted: 2013年10月20日(日) 18:34
by はじめたばかり

コード:

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

int getrandom(int min,int max);

void main()
{
	int i,total=0;
	int x[6]={0,37,49,52,20,40};
	int n[6]={0,1,2,3,4,5};
	int v[6];    //マーキング
	int t=0;	//カウント
	int r=0,range=0;
	
	srand((unsigned)time(NULL));
	
	while(t != 5){
		for(i=1;i<=5;i++){
			if(v[i]==0){
				total+=x[i];
			}
		}
		//printf("total=%d\n",total);
		r=getrandom(0,total);
		//printf("r=%d\n",r);
		for(i=1;i<=5;i++){
			if(v[i]==0 && range<r && r<=x[i]+range){
				printf("%d\n",n[i]);
				v[i]=1;
				t++;
				break;
			}
			range=x[i]+range;
		}
		total=0;
	}
}

int getrandom(int min,int max)
{
	return min+(int)(rand()*(max-min+1.0)/(1.0*RAND_MAX));
}
ルーレット選択とうものを簡単に書いてみたんですが、26行目の文を表示させると乱数が何回も発生してしまうのでそこをなおしたいです。

Re: 乱数について

Posted: 2013年10月20日(日) 18:40
by みけCAT
少なくともメモリ破壊はなさそうですし、最適化のバグもそうそう起こらないと思います。
理想の出力例を示していただけますか?

Re: 乱数について

Posted: 2013年10月20日(日) 18:42
by みけCAT
おそらく、まず配列xの内容を先に累積和に変換し、
出た乱数の値がxのどこの間に当たるかを二分探索するのがいいと思います。

Re: 乱数について

Posted: 2013年10月20日(日) 18:44
by みけCAT
配列vの内容が不定なので、たまたまv[1]~v[5]がすべて0になっていなかった場合、無限ループになりそうです。

Re: 乱数について

Posted: 2013年10月20日(日) 18:55
by はじめたばかり
みけCAT さんが書きました:配列vの内容が不定なので、たまたまv[1]~v[5]がすべて0になっていなかった場合、無限ループになりそうです。

コード:

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

int getrandom(int min,int max);

void main()
{
	int i,total=0;
	int x[6]={0,37,49,52,20,40};
	int n[6]={0,1,2,3,4,5};
	int v[6]={0,0,0,0,0,0};    //マーキング
	int t=0;	//カウント
	int r=0,range=0;
	
	srand((unsigned)time(NULL));
	
	while(t != 5){
		for(i=1;i<=5;i++){
			if(v[i]==0){
				total+=x[i];
			}
		}
		//printf("total=%d\n",total);
		r=getrandom(0,total);
		//printf("r=%d\n",r);
		for(i=1;i<=5;i++){
			if(v[i]==0 && range<r && r<=x[i]+range){
				printf("%d\n",n[i]);
				v[i]=1;
				t++;
				range=0;
				break;
			}
			range=x[i]+range;
		}
		total=0;
	}
}

int getrandom(int min,int max)
{
	return min+(int)(rand()*(max-min+1.0)/(1.0*RAND_MAX));
}

12行目と32行目を追加したんですが、やはりダメでした。

Re: 乱数について

Posted: 2013年10月20日(日) 18:59
by みけCAT
12行目を追加したのはいいことだと思います。
32行目は蛇足だという気がしますが、仕様がわからないので何とも言えません。

Re: 乱数について

Posted: 2013年10月20日(日) 19:02
by みけCAT
そもそも、最初の「乱数が何回も発生してしまう」というのは仕様ではないのですか?
乱数を1回しか発生させずに全てを選択したいということですか?
逆に、最初の26行目の文を表示させなければ、乱数が何回も発生してしまうことはない、という認識でいいですか?

Re: 乱数について

Posted: 2013年10月20日(日) 22:19
by はじめたばかり
みけCAT さんが書きました:そもそも、最初の「乱数が何回も発生してしまう」というのは仕様ではないのですか?
乱数を1回しか発生させずに全てを選択したいということですか?
逆に、最初の26行目の文を表示させなければ、乱数が何回も発生してしまうことはない、という認識でいいですか?
そうですが、乱数が何回も発生してしまいプログラムが終わらないんです。
乱数を発生させて1,2,3,4,5の数字だしたいんです。乱数の値が0~37の間なら1、38~86なら2、87~138なら3、139~158なら4、159~198なら5という感じです。一つ表示させたら、残りの4つの数字の中からまた乱数で表示させます。
26行目を表示させなければ、プログラムは動くときが多いんですが時間が少しかかるのでもっと精度の高いものを作りたいと思ってます。乱数が何回表示されてるかはわかりません。

Re: 乱数について

Posted: 2013年10月20日(日) 22:37
by みけCAT
みけCAT さんが書きました:おそらく、まず配列xの内容を先に累積和に変換し、
出た乱数の値がxのどこの間に当たるかを二分探索するのがいいと思います。
この方針で実装してみました。

コード:

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

#define DEBUG

int getrandom(int min,int max);

#define N_MAX 5

int main(void) {
	int x[N_MAX+1]={0,37,49,52,20,40};
	int n[N_MAX]={1,2,3,4,5};
	int got[N_MAX]={};
	int i;

	srand((unsigned)time(NULL));

	for(i=0;i<N_MAX;i++) {
		int ruiseki[N_MAX+1];
		int j;
		int r;
		int left,right,mid;
		int nowid;
		ruiseki[0]=x[0];
		for(j=1;j<=N_MAX;j++) {
			ruiseki[j]=ruiseki[j-1];
			if(!got[j-1])ruiseki[j]+=x[j];
		}
		r=getrandom(0,ruiseki[N_MAX]-1);
#ifdef DEBUG
		fprintf(stderr,"ruiseki: ");
		for(j=0;j<=N_MAX;j++)fprintf(stderr,"%d ",ruiseki[j]);
		fprintf(stderr,"\nr = %d\n",r);
#endif
		left=0;right=N_MAX-1;
		while(left<=right) {
			mid=(left+right)/2;
			if(ruiseki[mid]>r)right=mid-1; else left=mid+1;
		}
		nowid=left-1;
#ifdef DEBUG
		fprintf(stderr,"nowid = %d\n",nowid);
#endif
		printf("%d\n",n[nowid]);
		got[nowid]=1;
	}
	return 0;
}

#if 0
/* この乱数ではmaxを超える値が出る可能性がある */
int getrandom(int min,int max)
{
	return min+(int)(rand()*(max-min+1.0)/(1.0*RAND_MAX));
}
#else
/* 苦Cより http://9cguide.appspot.com/21-02.html */
int GetRandom(int min,int max)
{
	return min + (int)(rand()*(max-min+1.0)/(1.0+RAND_MAX));
}

int getrandom(int min,int max){return GetRandom(min,max);}
#endif

Re: 乱数について

Posted: 2013年10月22日(火) 20:33
by はじめたばかり
52行目のコメントについてなんですが、なぜmaxの値を超える数字が出る可能性があるんですか?

Re: 乱数について

Posted: 2013年10月22日(火) 21:24
by みけCAT
例えばmin=0,max=1で、rand()でRAND_MAXが返ってきたとすると、
RAND_MAX*(1-0+1.0)/(1.0*RAND_MAX)=(RAND_MAX*2.0)/(1.0*RAND_MAX)=2.0
となり、maxの1を超える可能性があると思いました。