シードを固定した乱数

シードを固定した乱数 どう書く?org からですが、シードを固定した乱数を発生させます。 gawk などではシードがアーキテクチャー間でも固定されて乱数が発生されるため、gawk 3.1.6: rand.awk test case alignment problem のような問題もありましたが、現在は直っているようです。 一方、手元の awk のバリアント間では mawk が rand() 関数だけではシードが固定されませんので、srand() 関数を用いてシードの初期化を行います。

#! /usr/local/bin/nawk -f
# fixed_seed_rand.awk
# シードを固定した乱数
# usage: nawk -f fixed_seed_rand.awk [seed]

BEGIN {
    seed = ARGV[1] ? ARGV[1] : 0;
    srand(seed);
    print rand();
}

実行してみると分かりますが、それぞれ値そのものは異なります。

$ nawk -f fixed_seed_rand.awk 0
0.840188

$ gawk -f fixed_seed_rand.awk 0
0.566305

$ mawk -f fixed_seed_rand.awk 0
0.131538

$ busybox awk -f fixed_seed_rand.awk 0
0.840188

awk のバリアント間で値を固定するには自分で乱数を実装するのが良さそうです。

そこで、ここでは比較的簡単に実装できる Wichman-Hill の乱数を使ってみます。

#! /usr/local/bin/nawk -f
# wichman_hill.awk
# Wichman-Hill の乱数を発生させる
# usage: gawk -f wichman_hill.awk

BEGIN {
    for (i = 1; i <= 10; i++) {
        print wichman_hill();
    }
}

# Wichman-Hill の乱数
#   out:    Wichman-Hill の乱数
function wichman_hill(  r) {
    ix = ix ? ix : 1;
    iy = iy ? iy : 1;
    iz = iz ? iz : 1;
    ix = int(171 * (ix % 177) - 2 * (ix / 177));
    iy = int(172 * (iy % 176) - 2 * (iy / 176));
    iz = int(170 * (iz % 178) - 2 * (iz / 178));
    if (ix < 0) {
        ix += 30269;
    }
    if (iy < 0) {
        iy += 30307;
    }
    if (iz < 0) {
        iz += 30323;
    }
    r = ix / 30269 + iy / 20307 + iz / 30323;
    while (r >= 1) {
        r = r - 1;
    }
    return r;
}

ix, iy, iz は次の乱数発生時に引き継がれていくことで毎回異なる乱数を発生させますので、ここではグローバル変数にしています。

$ nawk -f wichman_hill.awk
0.0196104
0.355991
0.732857
0.841031
0.898184
0.147954
0.748403
0.735806
0.53691
0.592371

$ mawk -f wichman_hill.awk
0.0196104
0.355991
0.732857
0.841031
0.898184
0.147954
0.748403
0.735806
0.53691
0.592371

$ gawk -f wichman_hill.awk
0.0196104
0.355991
0.732857
0.841031
0.898184
0.147954
0.748403
0.735806
0.53691
0.592371

このようにすることで awk のバリアント間で乱数を固定することができます。

tag_nawk.pngtag_nawk.pngtag_nawk.pngtag_nawk.png