私はいつも最善の方法が何であるか疑問に思いました。いいねMIN
Bashのランダム性、つまり、とのMAX
間で任意の正の整数を取得するプロセスは何ですか?
- 範囲は任意に大きくすることができます(または少なくとも最大2 32 -1)。
- 値は均等に分布されます(つまり、偏見はありません)。
- 効果がある
Bashでランダム性を達成する効果的な方法は、$RANDOM
変数を使用することです。しかし、これは 0 と 2 15 -1 の間の値だけをサンプリングするので、すべての目的には十分ではないかもしれません。人々は通常モジュロを使用して目的の範囲に置きます。
MIN=0
MAX=12345
rnd=$(( $RANDOM % ($MAX + 1 - $MIN) + $MIN ))
$MAX
さらに、これは正確に2 15 -1 = 32767で除算されない限り偏向を生成します。たとえば、$MIN
0と9の場合、絶対32768または32769にすることはできない$MAX
ため、0〜7の値が8と9の値よりわずかに高い可能性があります。$RANDOM
この偏向は、範囲が増加するにつれてさらに激しくなる。たとえば、$MIN
0が$MAX
9999の場合、0から2767までの確率は4/32767ですが、 2768から9999までの確率は3/32767にすぎません。
したがって、上記の方法は条件3を満足するが、条件1及び2を満足しない。
条件1と2を満たすように努力しながら、これまでに考えた最良の方法は、/dev/urandom
次のものを使用することです。
MIN=0
MAX=1234567890
while
rnd=$(cat /dev/urandom | tr -dc 0-9 | fold -w${#MAX} | head -1 | sed 's/^0*//;')
[ -z $rnd ] && rnd=0
(( $rnd < $MIN || $rnd > $MAX ))
do :
done
基本的に、暗号学的に強力な擬似乱数ジェネレータが/dev/urandom
必要/dev/random
な場合場所時間またはハードウェア乱数ジェネレータ)、10進数以外のすべての文字を削除し、出力を長さに合わせて折りたたみ、先行$MAX
ゼロを削除します。偶然 0 だけ取得すると空になるので、$rnd
この例ではrnd
に設定されます0
。結果が私たちの範囲外であることを確認し、そうであれば繰り返します。ループをシミュレートするという精神では最初から定義されていないdo ... while
ので、ボディが少なくとも1回実行されるように、whileループの「ボディ」をガードに強制的に適用しました。rnd
ここでは条件1と2を満たしていたと思いましたが、今は条件3を台無しにしました。これは少し遅いです。最大1秒程度かかります(運が良ければ10分の1秒程度)。実際にループが終了するという保証もありません(時間が増えるにつれて終了確率は1に収束しますが)。
Bashでは、事前に指定され、潜在的に大きな範囲内で偏向されていない任意の整数を取得する効率的な方法はありますか? (時間が許せば調査を続ける予定ですが、その間、ここで誰かが良いアイデアを持っているかもしれないと思いました!)
回答紙
最も基本的な(したがって移植可能な)アイデアは、十分に長いランダムなビット文字列を生成することです。任意のビット文字列を生成する方法はいくつかあります。 bashの組み込み変数を使用するか、and(または)を
$RANDOM
使用できます。乱数が大きい場合は再起動してください。od
/dev/urandom
/dev/random
$MAX
あるいは、外部ツールを使用することもできます。
- Perlソリューション
- 利点:携帯性に優れ、シンプルで柔軟です。
- 対照:2 32 -1より大きい数字には適していません。
- Pythonソリューション
- 利点:シンプルで柔軟性があり、大容量データにも適しています
- 欠点:携帯性が悪い
- zshソリューション
- 利点:zshを使用している人にはまだ良いです。
- 反対:おそらく携帯性が低下します。
- Perlソリューション