乱数生成法で最初の乱数の値は固定されるのか確認したい

このQ&Aのポイント
  • 乱数生成法により生成された最初の乱数の値が固定されるのかを確認したいです。
  • 特定の乱数生成法を使用し、生成された乱数の最初の値が固定されるかどうかを検証したいです。
  • C言語の特定の乱数生成法を使用し、生成された乱数列の最初の値が固定されるかどうかを確かめたいです。
回答を見る
  • ベストアンサー

ある乱数生成法により,生成した最初の乱数の値は固定するか確かめて頂きた

ある乱数生成法により,生成した最初の乱数の値は固定するか確かめて頂きたいです. 0.0から1.0までの一様乱数を発生させる方法です. C言語のコードは以下に載せます. #define IA 16807 #define IM 2147483647 #define AM (1.0/IM) #define IQ 127773 #define IR 2836 #define MASK 123459876 float ran0(long *idum) { long k;   float ans; *idum ^= MASK; k=(*idum)/IQ; *idum=IA*(*idum-k*IQ)-IR*k; if (*idum < 0) *idum += IM; ans=AM*(*idum); *idum ^= MASK; return ans; } この乱数生成法をBVAで,計算の中で繰り返し用いようとしています. idumを任意の整数値に設定・再設定すれば乱数列が初期化されると書いてあったため,idumの値を変えてみましたが,生成された乱数の最初の値は固定されたままでした. そこで,もともとこの乱数生成法がそのようになっているのかを教えて頂きたいです. よろしくお願いします.

質問者が選んだベストアンサー

  • ベストアンサー
  • sinisorsa
  • ベストアンサー率44% (76/170)
回答No.2

Cの関数ran0の中の最初の *idum ^= MASK; で、関数の外で設定されたidumの値を使って MASKとの間でビット毎に排他的論理和を取って います。当然、外で与えるidumの値が変われば 乱数の最初の値は変わります。 実際、メイン関数を作って、この関数をコンパイル して、実行してみましたが、そのように動いて います。 idumの値を変えても、乱数の初期値が変わらない とすれば、関数ran0の呼び方を間違えていると 思います。 ran0の引数はポインタであることを意識していますか? なお、Cの標準関数の中にも乱数発生関数randがあります。 これは、関数srandで初期化すれば、初期値を固定 できます。逆にいえば、普通は、randの初期値は 固定されません。 VBAにも乱数発生関数が組み込まれていると思いますが、 これらを使わない理由が何かあるのでしょうか。 乱数の統計的性質が余りよくないのは確かですが、 あなたのran0も同程度でしょう。 もっと性質のよい乱数発生アルゴリズムがあるはず ですので、ご調査ください。

jimysen
質問者

お礼

回答ありがとうございます. 丁寧な説明でわかりやすかったです.見直して行ってみたところ,解決することができました. 本当にありがとうございました.

その他の回答 (1)

  • f272
  • ベストアンサー率46% (7998/17100)
回答No.1

BVAというのが何の事だか分りませんが,C言語で書かれたプログラムで生成される最初の乱数の値は固定なんてことはありませんよ。 どういう使い方をしているのかな?

jimysen
質問者

お礼

回答ありがとうございます. BVAはExcelのVisual Basic for Applicationsのことです. 使い方はそのまま書いていますが,idumを0に設定しないならば,関数中の^演算のある2行は消してもよいと書かれていたため,その2行は消して行いました.また,消さない場合でも生成された最初の乱数は固定されたままでした. 回答によれば固定されることはないということなので,間違っているところがあると思うので見直してみます. 迅速な回答をありがとうございます.

関連するQ&A

  • 本に掲載されたC言語の乱数発生方法をVBAでかく方法が知りたいです.

    本に掲載されたC言語の乱数発生方法をVBAでかく方法が知りたいです. 0.0から1.0までの一様乱数を発生させる方法です. C言語のコードは以下に載せます. #define IA 16807 #define IM 2147483647 #define AM (1.0/IM) #define IQ 127773 #define IR 2836 #define MASK 123459876 float ran0(long *idum) { long k;   float ans; *idum ^= MASK; k=(*idum)/IQ; *idum=IA*(*idum-k*IQ)-IR*k; if (*idum < 0) *idum += IM; ans=AM*(*idum); *idum ^= MASK; return ans; }  以下に自分でVBAでかいてみたコードを載せます. Sub 乱数発生() Const IA As Integer = 16807 Const IM As Long = 2147483647 Const AM = (1# / IM) Const IQ As Long = 127773 Const IR As Integer = 2836 Const MASK As Long = 123459876 Dim k As Long Dim ans As Single Dim idum idum = idum Xor MASK k = (idum) / IQ idum = IA * (idum - k * IQ) - IR * k If idum < 0 Then idum = idum + IM ans = AM * (idum) idum = idum Xor MASK End Sub  最初と最後のidum = の式の説明に排他的論理和をとるという説明が書いてあったので,^ではなくXorと書きました.これで一応ansは1より小さい数値がでましたが,C言語の数値と合いませんでした. プログラムのことはほとんどわからないので,教えて下さい. よろしくお願いします.

  • 16bitで乱数を生成する方法

    cのrand()関数を使用せずに、 16bitの整数演算で、乱数を生成したいのですが、 何か良い方法はありませんでしょうか? 以下のように作ってみたのですが、時と場合によっては、 繰り返しになるみたいです。 なお、8bitのPICマイコンを使用しております。 宜しくお願い致します。 ****longを2バイトとする。*** #define _ULONG unsgined long _ULONG g_ulSeed = 31; _ULONG rand2() { _ULONG ulTemp; g_ulSeed = ( 2045 * g_ulSeed ) % 32768; g_ulSeed = g_ulSeed % 0xfff0;      // 上位8bitと下位8bitの入れ替え ulTemp = ( g_ulSeed & 0xff ) << 8; g_ulSeed = ulTemp | (g_ulSeed >> 8 ); return g_ulSeed; }

  • 円周率 πの値

    円周率πの値を求めたのですがNを大きくすると3.1415・・・に近づくはずですが、うまくいきません。どうすればいいのか検討がつきませんので、ご指摘お願いします。 float myrand() { float ans; ans=(float)rand()/(RAND_MAX); return(ans); } main() { int i,sum; long N; float ans,x,y,r,p; srand((unsigned)time(NULL)); sum=0; for(N=10;N<=1000000;N*=10){ for(i=10;i<N;i++){ x=myrand(); y=myrand(); r=x*x+y*y; if(r<=1){ sum++; } } ans=(float)(sum)/N; p=ans*4; printf("%d %f\n",N,p); } getch(); exit(0); } 実行結果 10 0.000000 100 2.640000 1000 3.440000 10000 3.483600 100000 3.490640 1000000 3.491268

  • 高精度乱数関数

    rand()の値をRAND_MAX+1で割ると、[0, 1)の範囲になりますよね。 もし、RAND_MAX+1が2の乗数なら、浮動小数において結果は丸め誤差を含んでいないはずですよね。 unixのgccでコンパイルしたのですが、RAND_MAXの値は32767だったので、 #define (RM RAND_MAX + 1) #define RND ((long double)rand()) long double x; x = RND / RM + RND / RM / RM + RND / RM / RM / RM + RND / RM / RM / RM / RM ・ ・ ・; とすれば、精度の高い[0, 1)区間の乱数関数を作ることはできますか? この論理に間違いがあれば指摘してください。

  • ハッシュを使った擬似乱数

    予測不能な擬似乱数列を生成する際に、よく一方向ハッシュの性質を利用する 場合があります。一方向ハッシュの生成源として内部状態が与えられますが、 内部状態のbitサイズはどの程度にしたらよいでしょうか?   [種(カウンタの初期値)]        |        |        ↓ ┌→[内部状態(カウンタ)]―┬―→(一方向ハッシュ)――→擬似乱数列 |                 | |                 ↓ |               [1増加] |                 | └―――――――――――┘ ※ 暗号技術入門 秘密の国のアリス 結城 浩 著      ――第12章 乱数 Fig.12.5 より 極端な例として鍵(種)のサイズを32bit(C言語でunsigned long型)、値を0とします。 |0000 0000|0000 0000|0000 0000|0000 0000| 上記の値でハッシュ値を取ります。ハッシュアルゴリズムがSHA1の場合、 以下のような値が得られます(と思います)。 a = -1099956234 b = -343932961 c = -1287651379 d = -84150665 e = -1099170433 これらの値から鍵の値を得ることは困難なので、ハッシュ値によって生成された 擬似乱数は予測不能であるといえます。また、鍵の値を1だけ加算させて次の擬似乱数 を生成します。一般的にこのようにして乱数列は生成されます。 上記の例では32bitのとり得る値は0~4294967295です。鍵の値を一つずつ試し ていけば、それほど時間をかけることなく乱数の予測不能性は破られてしまいます。 ここで鍵の値を256bitとしました。 |0000 0000|0000 0000|0000 0000|0000 0000| |0000 0000|0000 0000|0000 0000|0000 0000| |0000 0000|0000 0000|0000 0000|0000 0000| |0000 0000|0000 0000|0000 0000|0000 0000| |0000 0000|0000 0000|0000 0000|0000 0000| |0000 0000|0000 0000|0000 0000|0000 0000| |0000 0000|0000 0000|0000 0000|0000 0000| |0000 0000|0000 0000|0000 0000|0000 0000| しかしこれだと1加算しただけではビット全体に対して変化が少なすぎます。 |0000 0000|0000 0000|0000 0000|0000 0000| |0000 0000|0000 0000|0000 0000|0000 0000| |0000 0000|0000 0000|0000 0000|0000 0000| |0000 0000|0000 0000|0000 0000|0000 0000| |0000 0000|0000 0000|0000 0000|0000 0000| |0000 0000|0000 0000|0000 0000|0000 0000| |0000 0000|0000 0000|0000 0000|0000 0000| |0000 0000|0000 0000|0000 0000|0000 0001|← 2005年に中国の大学の研究チームによってSHA1の弱衝突耐性が破られてしまいました。 現段階ではSHA1に変わる新しいアルゴリズムは発見されていません。(SHA2が作られましたが、 これはSHA1のbit数を拡張しただけで基本設計は変わっていません)なのでハッシュ値を 生成させる値もなるべく変化に富んだ値を与えることが推奨されています。 まとめると、   ・鍵(種)を総当り攻撃されないようにbit数を大きくしなけらばならない。   ・bit数を大きくすると1加算したときに変化が小さすぎる。   ・最初の図の手法は同記の文献に書いてあったもので、なるべく変えたくない。    (実際に使われる手法はある程度保障されているから) の制約があります。なので”bit数をどの程度にしたら適当か???”というのが質問です。 また、これらの問題を打開する方法もあればよいのですが、、、

  • 変数に入る値

    以下の1部のコードがあるとします。 #include<stdio.h> #define N 3 #define M 3 int main(){ float i,j,k;    ・    ・ここのプログラムは省略します。    ・ for(i=0; i<N; i++){ for(j=0; j<N; j++){ for(k=0; k<M; k++){ c[i][j] += a[i][k] * b[k][j]; }}} このようなコードがあった場合、c[i][j] += a[i][k] * b[k][j];のところで 3個目のfor文の1回目のループの時、 c[i][j] += a[i][k] * b[k][j];の[i][j]や[i][k]、[k][j]にはいる値は c[0.000000][0.000000]+=a[0.000000][0.000000]~~~~~~~~ とかんがえられるでしょうか? i,j,kはint型のほうがよいですが、確認のためfloatにしました。 意味不明な質問ですみません。 よろしくお願いします。

  • nextDoubleが使えない?

    nextDoubleを使って,乱数で生成した値を○○.○や○○○.○といった 小数点第一位までに直したいのですが,乱数がそのまま出力され,上手くできません. いろいろ考えたのですが,原因が分かりませんでした. どこに問題があるのか,何が間違っているのか教えてください. 問題のプログラム //乱数生成 Date date = new Date(); Random rand = new Random(date.getTime()); //値を変換 for(int i=0; i<3; i++){  x[i] = (float)(XRANGE * rand.nextDouble());  y[i] = (float)(YRANGE * rand.nextDouble());  rgb[i] = (float)(rand.nextDouble()); } (補足)  XRANGE,YRANGEは500.0(double型)  配列は全てfloat型  importしているのは,   java.util.Random   java.util.Date   java.io.PrintStream   よろしくお願いします.

    • ベストアンサー
    • Java
  • モンテカルロ法の面積近似

    Mが2の32乗の、線形合同法で乱数を発生し、 モンテカルロ法を使って、 領域a = {(x,y)|x≧1,y≧2,(x-1)^2 + (y-2)^2 ≦1}の面積の近似値を計算するプログラムを作成し、これを利用してn=10000とした場合の上の領域の面積、および円周率πの近似値を求めよ。 (関数を使う) という課題が出たのですが、乱数の出し方?が変であまり近似されません(^_^;) どなたかどこが変か教えてください(>_<) これだと、2と4になってしまうんです(/_;) #include<stdio.h> #include<stdlib.h> #include<math.h> #define N 100 /*領域Rを含む面積T 領域R=求める面積*/ #define Nx 1 #define Ny 2 /*乱数を発生させる関数*/ unsigned long int random_g(unsigned long int x0, unsigned long int a, unsigned long int c); int main(){ unsigned long int x0, a, c, M; double x, y, s; int n, count_in, count_out; count_in = 0; count_out = 0; printf("x0: ", x0 ); scanf("%d", &x0); a = 61; c = 49; for(n = 0; n < 10000; n++){ /*乱数を発生*/ x = (random_g(x0, 4*a*n+1, c) / (double)4294967296)*Nx + 1; y = (random_g(x0, 4*a*n+1, c) / (double)4294967296)*Ny + 1; if(x >= 1 && y >= 1 && pow(x-1, 2) + pow(y-2, 2) <= 1) count_in++; else count_out++; } s = (double)count_in/(count_in + count_out)*Nx*Ny; printf("s = %f\n", s); printf("pi = %f\n", 2*s); return 0; } unsigned long int random_g(unsigned long int x0, unsigned long int a, unsigned long int c){ int i; x0 = (a*x0 + c); /*printf("%u\n", x0);*/ return x0; }

  • ニュートン法

    ケプラー方程式x-e*sin(x)-c=0の解をステップ数とともに出力するプログラムで、e,cはそれぞれ0.5と1です。 xに値を入力して計算させるのですが、どうしてもできません。 下のプログラムリストでおかしいところはどこでしょうか? // ニュートン法 x-e*sin(x)-c=0 #include <stdio.h> #include <math.h> #define e 0.5 #define c 1.0 #define K 10000 double fun(double x); double bibun(int i,double x); float m=1.0,n=1.0; int i=1; main(){ float x1,x2; float z; printf("初期値x0を入力して下さい\n"); scanf("%f",&x1); for(i=0;i<=K;i++){ x2 = x1 - fun(x1)/bibun(i,x1); x1 = x2; z = fun(x1); z = fabs(z); if(fabs(z)<=0.00001){ break; } if(i==K){ printf("収束しません\n"); exit(0); }    } printf("解 = %f\n",x1); printf("ステップ数 = %d",i); return 0; } // 関数f(x) double fun(double x1){ double r; r = x1 - e * sin(x1) - c; return r; } // 微分 double bibun(int i,double x1){ float p; if(i%2==1){ p = pow((-1.0),m)*e*sin(x1); m++; } else { p = pow((-1.0),n)*e*cos(x1); n++; } return p; }

  • 掃出法で連立一次方程式の解を求める

    掃出法で連立一次方程式の解を求めるプログラムを作ってみたのですが、ポインタと浮動小数点のエラーが出てしまい、実行できません。どこが間違っているのかさえ分からず困っています。訂正箇所を教えてください。宜しくお願い致します。 #include<stdio.h> #include<math.h> #include <float.h> #define N 3 #define EPSILON 1.0E-5 #define TRUE 1 #define FALSE 0 void sweep(int *flag); void swap(float *wk1,float *wk2); float a[N][N]={{ 2, 6, 3}, {-1, 5,-2}, {-2,-1, 6}}; float x[N],b[N]={6,3,14}; int flag; void main() { int i,j; for(i=0;i<N;i++) { for(j=0;j<N;j++) printf("%10.4f",a[i][j]); printf("%10.4f\n",b[i]); } flag=TRUE; sweep(&flag); if(flag==TRUE) { printf("連立方程式の解\n"); for(i=0;i=N;i++) printf("x[%d]=%10.4f\n",i+1,x[i]); } else printf("解なし\n"); } void swap(float *wk1,float *wk2) { float w; w=*wk1; *wk1=*wk2; *wk2=w; } void sweep(int *flag) { int i,j,k,ik; float ak,aik; for(k=0;k<N;k++) { ak=a[k][k]; if(fabs(ak)<=EPSILON) { ik=k+1; while((ik<N)&&(fabs(a[ik][k])<EPSILON)) ik++; if(ik<N) { for(j=k;j<N;j++) swap(&a[k][j],&a[ik][j]); swap(b[k],b[ik]); ak=a[k][k]; } else { printf("ピボットが零です\n"); *flag=FALSE; goto end; } } for(j=k;j<N;j++) a[k][j]=a[k][j]/ak; b[k]=b[k]/ak; for(i=0;i<N;i++) { if(i!=k) { aik=a[i][k]; for(j=k;j<N;j++) a[k][j]=a[i][j]-aik*a[k][j]; b[i]=b[i]-aik*b[k]; } } for(k=0;k<N;k++) x[k]=b[k]; end:; } }