1. 概要

ランダムな数値は、シミュレーションのユースケースでバイアスのない数値を選択する必要がある場合に非常に役立ちます。 このチュートリアルでは、Linux環境で乱数を生成するいくつかの一般的な方法を学習します。

2. 疑似乱数ジェネレータ

定義上、ランダムな数値は予測できません。 一方、コンピューティングマシンは、設計上、deterministic出力を生成します。 そのため、それらによって生成されるランダム数は、真にランダムではなく、疑似ランダムのみです。

疑似乱数ジェネレーター(PRNG)は、計算アルゴリズムを使用して、ランダムな結果の大きなシーケンスを生成します。 ただし、実際には、このようなシーケンスのすべての値は、シード値と呼ばれる初期値に依存します。 シード値とアルゴリズムがわかれば、シーケンス全体を正確に決定でき、すべての値を簡単に予測できます。

キャッチは、シードが不明であり、アルゴリズムが推測するのに十分複雑である限り、シーケンスはランダムに見えるということです。 したがって、最も一般的な使用例では、PRNGを使用しても安全です。 ただし、ユースケースがランダム性に強く依存している場合は、ハードウェアを使用してランダムな数値を生成する物理的な方法に切り替えます。

次のいくつかのセクションでは、一般的なUnixユーティリティを使用した疑似乱数の生成に焦点を当てます。

3. $ RANDOM in Bash

1から6までの数字で列挙されたサイコロを振るイベントをシミュレートしたいとします。

これを行うには、疑似乱数を与える組み込みのBash変数である$RANDOMを使用できます。

$ echo $RANDOM
30627
$ echo $RANDOM
10419

$ RANDOMを使用すると、は0から32767までの番号を取得します。 ただし、この場合、16の間のランダム値制限する必要があるため、モジュロ(%)演算子を使用して値を制限できます。 min =1max= 6:の間

$ cat dice.sh
#!/bin/bash

function roll_dice {
    min=1
    max=6
    number=$(expr $min + $RANDOM % $max)
    echo $number
}

ここではシード値を指定しなかったことに注意してください。つまり、Bashはデフォルトのシード値を使用してランダムシーケンスを生成します。 この関数を同時に呼び出して2つのシーケンスを生成すると、同じシーケンスを取得する可能性が高くなります。

したがって、シード値を明示的に初期化することにより、シード値にバリエーションを導入することをお勧めします

RANDOM=$$

2つの呼び出しは異なるプロセスIDを持つことがわかっているので、シード値としてPID($$)を使用できます。

最後に、roll.shスクリプトを介してこの関数を呼び出しましょう。

$ cat roll.sh
#!/bin/bash
. ./dice.sh
roll_dice
$ ./roll.sh
4
$ ./roll.sh
3
$ ./roll.sh
5

4. awkを使用する

awk は、テキストファイルを操作するための便利な言語およびUnixユーティリティです。 awkを使用してランダムな数値を生成する方法を見てみましょう。

4.1. データセット

さまざまなグループに属する学生の名前を含むファイルstudents.txt、があるとします。

$ cat students.txt
Bryan,Roger,Christina
Rishabh,Mary,Rose
Paul,Vikram,Yasim
Leo,Immy,Kudrat

現在、各グループからランダムに1人の生徒を選択する必要があります。

4.2. srand()および rand()

awk では、 2つの関数、つまりsrand()とrand()にアクセスできます。これらの関数は、0から1までのランダムな浮動小数点数を生成できます。 この場合、 srand()は、ランダムシーケンスを生成するためのシード値を初期化するのに役立ちます。

awkスクリプトをchoose.awkファイルに記述しましょう。

#!/bin/awk
BEGIN {
    FS=",";
    srand(seed);
}

{
    field=int(1.0 + rand()*NF)
    print $field
}

基本的に、フィールドセパレーター(FS)の1回限りの初期化を実行し、BEGINブロックにシードします。 後で、浮動小数点値をその行のフィールド数(NF)で乗算することにより、整数値にスケーリングします。

最後に、 -v フラグを使用してシード値を外部変数として指定することにより、スクリプトを実行してみましょう。

$ awk -v seed=$RANDOM -f choose.awk students.txt
Christina
Rose
Yasim
Kudrat

もちろん、これを複数回実行して、実際に毎回ランダムな結果が得られていることを確認できます。

5. 疑似デバイスファイルの使用

内部的には、数値はビットとして格納されます。 したがって、ランダムな数値を生成する別の方法は、ランダムなバイトを生成することです。 このセクションでは、疑似デバイスファイルをPRNGとして使用します。

5.1. / dev /randomおよび/dev / urandom

Unixでは、すべてがファイルであり、ファイルシステムの /dev仮想ディレクトリの下にマウントされるデバイスも含まれます。 さらに、Unixには、実際には実際のハードウェアに関連付けられていない一連の特別な疑似デバイスファイルもあります。 これらの中で、 / dev/randomと/dev/ urandomは、PRNGとして機能する2つの疑似デバイスファイルです。

$ ls -l /dev/*random
crw-rw-rw- 1 root root 1, 8 Oct 14 13:30 /dev/random
crw-rw-rw- 1 root root 1, 9 Oct 14 13:30 /dev/urandom

ご覧のとおり、すべてのユーザーはこれらのファイルに対して読み取り/書き込みを行うことができますが、実行( x )特権を持っているユーザーはいません。

興味深いことに、 Unixカーネルは、さまざまなデバイスからノイズの多いデータを収集し、それらをエントロピーの内部プールに転送します。 さらに、 / dev /randomおよび/dev / urandom は、このノイズに内部的にアクセスして、ランダムなバイトのデータを生成できます。

これらすべてが内部でどのように機能するかについての基本的な理解を持って、それらがどのように異なるかを見てみましょう。 ええと、urandomの「u」はunlimitedを表します。 つまり、本質的には、エントロピープールに含まれるエントロピーが要求を満たすために必要なエントロピーよりも少ない場合でも、 / dev /urandomがブロックされることはありません。 ただし、このような場合、 / dev /randomはブロックされます。  したがって、ランダム性と遅延の受け入れ基準に応じて、正しい選択を行う必要があります。

5.2。 ランダムバイトからの乱数

これらの疑似デバイスの理論的理解を利用して、サイズ4バイトのランダムな整数を生成しましょう。 そのために、ddコマンドを使用できます。

# dd if=/dev/urandom of=~/random_number count=4 bs=1
4+0 records in
4+0 records out
4 bytes copied, 0.0002276 s, 17.6 kB/s

基本的に、4バイトのデータを/dev / urandom から〜/random_numberにコピーしています。 データはrawバイトで保存されるため、catなどの通常のコマンドを使用してデータを読み取ることはできません。 代わりに、 odコマンドを使用して生のバイトを読み取り、整数を形成する必要があります。

$ od -An --format=dI ~/random_number
   449690100

フォーマットをdI(10進整数)として指定したため、odはそれを整数として読み取ることができます。 また、 -An を使用して、出力からのオフセットアドレスフィールドを抑制しました。

6. 結論

このチュートリアルの目的は、一般的なUnixユーティリティを利用してランダムな数値を生成することでした。

疑似乱数ジェネレーターの基本的な理解を深めることから始め、 Bash、awk、疑似デバイスファイルなどのいくつかのユーティリティを調べてさまざまなユースケースを解決しました。