mwcrans(3M)

名前
mwcrans - 繰り上げ付き乗算による疑似乱数生成関数

形式

cc [ flag ... ] file ... -lsunmath -lm [ library ... ]

#include <sunmath.h>

int i_mwcran_(void);

unsigned int u_mwcran_(void);

long i_lmwcran_(void);

unsigned long u_lmwcran_(void);

long long i_llmwcran_(void);

unsigned long long u_llmwcran_(void);

float r_mwcran_(void);

double d_mwcran_(void);

void i_mwcrans_(int *x, const int *n, const int *l, const int *u);

void u_mwcrans_(unsigned *x, const int *n, const unsigned *l, const unsigned *u);

void i_lmwcrans_(long *x, const int *n, const long *l, const long *u);

void u_lmwcrans_(unsigned long *x, const int *n, const unsigned long *l, const unsigned long *u);

void i_llmwcrans_(long long *x, const int *n, const long long *l, const long long *u);

void u_llmwcrans_(unsigned long long *x, const int *n, const unsigned long long *l, const unsigned long long *u);

void r_mwcrans_(float *x, const int *n, const float *l, const float *u);

void d_mwcrans_(double *x, const int *n, const double *l, const double *u);

void i_init_mwcrans_(void);

void smwcran_(const int *seed);

void i_set_mwcrans_(const int *p);

void i_get_mwcrans_(int *p);

機能説明
これらの関数は、Marsaglia により開発された繰り上げ付き乗算 (multiply-with-carry) アルゴリズムを使用し、 疑似乱数のシーケンスを生成します。乗数を M、シードの初期値を X、キャリ ーの初期値を C (すべて 32 ビット整数) とすると、このアルゴリズムは、次のよ うにして新しいシードとキャリーを生成します。

	1. Z = X*M + C  (Z 64 ビット整数)
	2. 新しいシード  X = Z の下位 32 ビット
	3. 新しいキャリー C = Z の上位 32 ビット

(M*2**32 - 1) と (M*2**31 - 1) は両方とも素数であると仮定すると、シ ードとキャリーのシーケンスの周期は M*2**31 - 1 です。

上記関数は内部的に 32 ビットの繰り上げ付き乗算による生成関数 mwcran0 と mwcran1 を使用します。mwcran0 で使用される乗数は 526533 (0x808C5) で、mwcran1 で使用される乗数は 557325 (0x8810D) です。これら生成関数の 周期は両方とも約 2**50 です。これらの生成関数については、次の説明を参照して ください。

u_mwcran_() は mwcran0 を呼び出し、32 ビット符号なし整数の疑似乱数 (0 から 2**32 - 1 まで) を戻します。

i_mwcran_() は u_mwcran_() を呼び出し、その結果の最上位ビットを マスクオフし、32 ビット符号付き整数の疑似乱数 (0 から 2**31 - 1 まで) を戻します。

u_llmwcran_() は mwcran0 と mwcran1 の両方を呼び出し、2 つの
 32 ビット値を一緒に連結し、64 ビット符号なし整数の疑似乱数 (0 から 2**64 - 1 まで ) を戻します。この乱数生成関数の周期は約 2**100 です。

i_llmwcran_() は u_llmwcran_() を呼び出し、その結果の最上位ビッ トをマスクオフし、64 ビット符号付き整数の疑似乱数 (0 から 2**63 - 1 まで) を戻しま す。

関数 i_lmwcran_() と u_lmwcran_() はロング整数型の疑似乱数を戻しま す。これらの数の範囲は、ロング整数型の幅によって異なります。つまり、long int が
 32 ビット幅 (つまり、ILP32 データモデル) の場合、これらの関数はそれぞれ i_mwcran_() や u_mwcran_() と同じです。long int が 64 ビット幅 (LP64 データモデル) の場合、これらの関数はそれぞれ i_llmwcran_() や u_llmwcran_() と同じです。

r_mwcran_() は単精度浮動小数点の疑似乱数 (範囲は [0,1)) を戻します。この関 数は、mwcran0 を繰り返し呼び出し、ランダムなビットのシーケンスを生成し、そ の結果をバイナリ小数部 0.xxxxxxxxxxxxxxx... として解釈し、浮動小数点形式に切り捨 てることにより、この値を生成します。結果の浮動小数点数のシーケンスは範囲 [0,1) で均一に分散されます。

d_mwcran_() は倍精度浮動小数点の疑似乱数 (範囲は [0,1)) を戻します。この関 数は、mwcran0 と mwcran1 を繰り返し呼び出し、ランダムなビットのシー ケンスを生成し、その結果をバイナリ小数部 0.xxxxxxxxxxxxxxx... として解釈し、倍精 度浮動小数点形式に切り捨てることにより、この値を生成します。結果の浮動小数点数の シーケンスは範囲 [0,1) で均一に分散されます。

i_mwcrans_(x, n, l, u) は mwcran0 を繰り返し 呼び出し、*l と *u の間に均一に分散される 32 ビット整数の疑似乱数 *n (x[0], x[1], ... x[*n - 1]) を生成します 。[*l,*u] = [0,0x7fffffff] の場合、i_mwcrans_() は、 i_mwcran_() を *n 回呼び出したときに生成される結果と同じ *n 乱数を生成します。

u_mwcrans_(x, n, l, u) は mwcran0 を繰り返し 呼び出し、*l と *u の間に均一に分散される 32 ビット符号なし整数の 疑似乱数 *n (x[0], x[1], ... x[*n - 1]) を生成し ます。[*l,*u] = [0,0xffffffff] の場合、u_mwcrans_() は、 u_mwcran_() を *n 回呼び出したときに生成される結果と同じ *n 乱数を生成します。

i_llmwcrans_(x, n, l, u) は mwcran0 と mwcran1 を繰り返し呼び出し、*l と *u の間に均一に分散される 64 ビット整数の疑似乱数 *n (x[0], x[1], ... x[*n - 1] ) を生成します。[*l,*u] = [0,0x7fffffffffffffff] の場合、i_llmwcrans_() は、 i_llmwcran_() を *n 回呼び出したときに生成される結果と同じ *n 乱数を生成します。

u_llmwcrans_(x, n, l, u) は mwcran0 と mwcran1 を繰り返し呼び出し、*l と *u の間に均一に分散される 64 ビット 符号なし整数の疑似乱数 *n (x[0], x[1], ... x[*n - 1]) を生成します。[*l,*u] = [0,0xffffffffffffffff] の場合、u_llmwcrans_() は、 u_llmwcran_() を *n 回呼び出したときに生成される結果と同じ *n 乱数を生成します。

関数 i_lmwcrans_() と u_lmwcrans_() は、ロング整数型の疑似乱数の配 列を生成します。生成される数の範囲は、ロング整数型の幅によって異なります。つまり 、long int が 32 ビット幅 (つまり、ILP32 データモデル) の場合、これらの関数はそ れぞれ i_mwcrans_() や u_mwcrans_() と同じです。long int が 64 ビット幅 (LP64 データモデル) の場合、これらの関数はそれぞれ i_llmwcrans_() や u_llmwcrans_() と同じです。

r_mwcrans_(x, n, l, u) は mwcran0 を繰り返し 呼び出し、(切り捨てエラーがでるまで) *l と *u の間に均一に分散される 単精度浮動小数点の疑似乱数 *n (x[0], x[1], ... x[*n - 1]) を生成します。*l がゼロで、*u が 1 よりも少 ない最大の単精度浮動小数点数である場合、r_mwcrans_() は、 r_mwcran_() を *n 回呼び出したときに生成される結果と同じ *n 乱数を生成します。

d_mwcrans_(x, n, l, u) は mwcran0 と mwcran1 を繰り返し呼び出し、(切り捨てエラーがでるまで) *l と *u の間に均一に分散される倍精度浮動小数点の疑似乱数 *n (x[0], x[1], ... x[*n - 1]) を生成します。*l がゼロで、 *u が 1 よりも少ない最大の倍精度浮動小数点数である場合、 d_mwcrans_() は、d_mwcran_() を *n 回呼び出したときに生成 される結果と同じ *n 乱数を生成します。

i_init_mwcrans_() は、mwcran0 と mwcran1 のシードとキャリー をデフォルト値に初期化します。

smwcran_(m) は、次の公式に従い、*m のスクランブル値で、 mwcran0 と mwcran1 のシードとキャリーを初期化します。

    mwcran0 の場合:
    	X0 = MWCRAN_SEED0 + (*m)*0x110005
    	C0 = MWCRAN_CARRY0 + (*m)*0x110005

    mwcran1 の場合:
    	X1 = MWCRAN_SEED1 + (*m)*0x100021
    	C1 = MWCRAN_CARRY1 + (*m)*0x100021

ここで、MWCRAN_SEED0、MWCRAN_CARRY0、MWCRAN_SEED1、および MWCRAN_CARRY1 は、それ ぞれ、mwcran0 と mwcran1 のシードとキャリーに対して i_init_mwcrans_() で確立されるデフォルトの初期値です。特に、ゼロと等しい
 *m で smwcran_(m) を呼び出すことは、 i_init_mwcrans_() を呼び出すことと等価です。この関数は、異なるシーケンス の乱数を取得するための簡単な方法です。より精密にシードとキャリーを制御するには、 i_set_mwcrans_() を使用します。

i_get_mwcrans_(p) と i_set_mwcrans_(p) は、それぞれ、 mwcran0 と mwcran1 の状態テーブルを取得および設定します。このテーブ ルは、両方の生成関数のシードとキャリーが入っている 4 つの整数 (p[0] から p[3] まで) の配列です。つまり、p[0] と p[1] には、 mwcran0 用のシードとキャリーが入っています。p[2] と p[3] には、 mwcran1 用のシードとキャリーが入っています。

使用例
次の例は、u_mwcran_() と u_mwcrans_() が整合性があることを検証し 、これらの関数が生成する数が均一に分散されているかどうかを調べます。

    /* u_mwcran*() を確認するサンプルプログラム */
    #include <sunmath.h>
    int main() {
    	unsigned x[1000],y[1000],i,lb,ub;
    	int n,hex1[16],hex2[16],hex3[16],seed,j;
    	double t1,t2,t3,v;
    	seed = 40;
    	/* 40 に初期化されたシードで、1000 個の符号なし整数の乱数を生成する。 */
    	smwcran_(&seed);
    	for (i=0;i<1000;i++) x[i] = u_mwcran_();
    	/* u_mwcrans_() で、同じ 1000 個の符号なし整数の乱数を生成する。 */
    	n = 1000; lb = 0; ub = 0xffffffff;
    	smwcran_(&seed);	/* reset seed */
    	u_mwcrans_(y,&n,&lb,&ub);
    	/* x と y が等しいことを検証する */
    	for (n=0,i=0;i<1000;i++) n |= (x[i]-y[i]);
    	if(n==0) printf("Array x is equal to array y.\n\n");
    	else     printf("***Error: array x is not equal to array y.\n\n");
    	/* 1000 個の乱数の 16 進数字の出現をカウントすることにより、
    	均一性を確認する。予想される値は 500。カウントは異なるシード値で
    	3 回繰り返される。*/
    	/* カウント配列 hex1[]、hex2[]、hex3[] を初期化する。*/
    	n = 1000; for (i=0;i<16;i++) hex1[i]=hex2[i]=hex3[i]=0;
    	/* シード値 1 で、1000 個の乱数の 16 進数字をカウントする。 */
    	seed = 1; smwcran_(&seed);
    	u_mwcrans_(x,&n,&lb,&ub);
    	for (i=0;i<n;i++) {
    	    j = x[i]; hex1[j&0xf] += 1; hex1[(j>>4)&0xf] += 1;
    	    hex1[(j>>8)&0xf] += 1; hex1[(j>>12)&0xf] += 1;
    	    hex1[(j>>16)&0xf] += 1; hex1[(j>>20)&0xf] += 1;
    	    hex1[(j>>24)&0xf] += 1; hex1[(j>>28)&0xf] += 1;
    	}
    	/* シード値 2 で、1000 個の乱数の 16 進数字をカウントする。 */
    	seed = 2; smwcran_(&seed);
    	u_mwcrans_(x,&n,&lb,&ub);
    	for (i=0;i<n;i++) {
    	    j = x[i]; hex2[j&0xf] += 1; hex2[(j>>4)&0xf] += 1;
    	    hex2[(j>>8)&0xf] += 1; hex2[(j>>12)&0xf] += 1;
    	    hex2[(j>>16)&0xf] += 1; hex2[(j>>20)&0xf] += 1;
    	    hex2[(j>>24)&0xf] += 1; hex2[(j>>28)&0xf] += 1;
    	}
    	/* シード値 3 で、1000 個の乱数の 16 進数字をカウントする。 */
    	seed = 3; smwcran_(&seed);
    	u_mwcrans_(x,&n,&lb,&ub);
    	for (i=0;i<n;i++) {
    	    j = x[i]; hex3[j&0xf] += 1; hex3[(j>>4)&0xf] += 1;
    	    hex3[(j>>8)&0xf] += 1; hex3[(j>>12)&0xf] += 1;
    	    hex3[(j>>16)&0xf] += 1; hex3[(j>>20)&0xf] += 1;
    	    hex3[(j>>24)&0xf] += 1; hex3[(j>>28)&0xf] += 1;
    	}
    	/* 各テストのカイ二乗を計算する。 */
    	t1 = t2 = t3 = 0.0;
    	for (i=0;i<16;i++) {
    	    v  = hex1[i]-500; t1 += v*v/500.0;
    	    v  = hex2[i]-500; t2 += v*v/500.0;
    	    v  = hex3[i]-500; t3 += v*v/500.0;
    	}
    	/* 結果を出力する。 */
    	printf("Expected value of each hex digit's appearance is 500.\n");
    	printf("Observed result with seed=1,2, and 3:\n");
    	printf("      Hex digit    Number of appearances with\n");
    	printf("                   seed=1     seed=2    seed=3\n");
    	for (i=0;i<16;i++) {
    	    printf("           %01X:       %4d       %4d      %4d\n",
    	    i,hex1[i],hex2[i],hex3[i]);
    	}
    	printf("                   ----------------------------\n");
    	printf("Chi-square value%7.2g   %8.2g   %8.2g\n",t1,t2,t3);
    	printf("Note:  A reasonable range of the Chi-square value is\n");
    	printf("       within [7.26, 25.00] which corresponds to the 5\n");
    	printf("       percent and 95 percent points of the Chi-square\n");
    	printf("       distribution with degree of freedom equal to 15.\n");
    	return 0;
    }

上記プログラムからの出力は次のようになります。

    Array x is equal to array y.

    Expected value of each hex digit's appearance is 500.
    Observed result with seed=1,2, and 3:
          Hex digit    Number of appearances with
                       seed=1     seed=2    seed=3
               0:        514        493       521
               1:        529        507       480
               2:        477        495       493
               3:        495        541       517
               4:        518        504       486
               5:        496        464       484
               6:        467        488       484
               7:        511        487       540
               8:        517        499       525
               9:        500        489       490
               A:        492        506       511
               B:        475        504       482
               C:        499        504       504
               D:        485        514       493
               E:        520        531       515
               F:        505        474       475
                       ----------------------------
    Chi-square value    9.5         11         11
    Note:  A reasonable range of the Chi-square value is
           within [7.26, 25.00] which corresponds to the 5
           percent and 95 percent points of the Chi-square
           distribution with degree of freedom equal to 15.

属性
次の属性については、 attributes(5) を参照してください。

属性タイプ | 属性値
使用条件 | SPROsunms、SPROlang (32 ビットライブラリ)
 | SP64sunms、SP64lang (64 ビットライブラリ)
インタフェース安定性 | 開発中
MT レベル | MT-安全

関連項目
addrans(3M), lcrans(3M), shufrans(3M), attributes(5)

注意事項
これらの関数は内部生成関数 mwcran0 と mwcran1 を共有するために、 お互いに独立していません。たとえば、i_init_mwcran_() を呼び出し、その後 に d_mwcran_() を呼び出したときの結果は、i_init_mwcran_() を呼び 出し、i_mwcran_() を呼び出し、その後に d_mwcran_() を呼び出した ときの結果とは異なります。(ただし、異なるスレッドの生成関数は独立しています。)

mwcran0 と mwcran1 で生成される乱数は、Marsaglia の Diehard 試験をク リアします。