1. ホーム
  2. スクリプト・コラム
  3. ルビートピックス

Rubyの乱数生成方法のまとめ

2022-01-03 15:19:18

数値は実際にはランダムではありません

どんなコンピュータも、純粋に計算だけで乱数を発生させることはできません。コンピュータができるのは、ランダムに見えるが実際にはランダムではない数字の集合である擬似乱数を生成することくらいです。

人間が見ると、これらの数字は確かにランダムです。短い繰り返しの列はなく、少なくとも人間の観察者にとっては完全にランダムである。しかし、十分な時間とやる気があれば、元の種を発見し、数列を再現し、数列の次の数字を推測することは可能である。

したがって、この論文で取り上げた方法は、暗号的に安全でなければならない数字の生成には、おそらく使うべきではないだろう。

前述したように、疑似乱数生成器(PRNG)は、新しい乱数を生成するたびに異なる配列が生成されるようにシードを設定する必要があります。どの方法も魔法のようなものではないことに留意してください。これらの一見乱数は、比較的単純なアルゴリズムと比較的単純な算数を使って生成されます。PRNGに種をまくことで,毎回違うところから始めることができます.PRNGに種を蒔かなければ、毎回同じ数字の列が生成されます。

Rubyでは、カーネルの#srandメソッドは引数なしで呼び出すことができます。これは、時間、プロセスID、シーケンス番号に基づいて乱数の種を選択します。プログラムの先頭の任意の場所でsrandを呼び出すだけで、実行するたびに異なる乱数らしき列が生成されます。このメソッドはプログラム起動時に暗黙のうちに呼ばれ、時刻とプロセスID(通し番号なし)でPRNGの種を蒔きます。

数字を生成する

プログラムが実行され、カーネルの#srandが暗黙的または明示的に呼び出されると、カーネルの#randメソッドを呼び出すことができるようになります。このメソッドは引数なしで呼ばれ、0から1までの乱数を返します。過去には、この数は通常、生成したい最大の数にスケーリングされており、おそらくto_iがそれを呼び出して整数に変換しています。

# Generate an integer from 0 to 10
puts (rand() * 10).to_i

しかし、Ruby 1.9.xを使用している場合、Rubyは物事を簡単にします。Kernel#randメソッドは引数を1つ取ることができます。この引数が任意の型の数であれば、Rubyは0からその数までの整数を生成する。

# Generate a number from 0 to 10
# In a more readable way
puts rand(10)

しかし、10 から 15 までの数字を生成したい場合はどうでしょうか。通常は0から5までの数字を生成して10に足すことになりますが、Rubyならもっと簡単にできます。

Kernel#randにRangeオブジェクトを渡すと、期待通りに範囲内の乱数整数を生成してくれます。

2種類の範囲に注意してください。rand(10..15) を呼び出すと、15 を含む 10 から 15 までの数値が生成され、 rand(10..15) (ドット 3 つ) を呼び出すと、15 を含まない 10 から 15 までの数値が生成されます。

# Generate a number from 10 to 15
# Including 15
puts rand(10..15)

非ランダム乱数

時には、ランダムに見える数字列が必要な場合もありますが、毎回同じ数字列を生成する必要があります。例えば、ユニットテストで乱数を生成する場合、毎回同じ数字の列を生成する必要があります。

ある配列で失敗したユニットテストは、次に実行したときにも失敗するはずで、次に別の配列を生成すれば失敗しないかもしれません。これを行うには、既知の定数値でカーネル#srandを呼び出します。

# Generate the same sequence of numbers every time
# the program is run
srand(5)
# Generate 10 random numbers
puts (0..10).map{rand(0..10)}

カーネルの #rand の実装は非rubyであることに注意してください。PRNGを抽象化することも、インスタンス化することもできません。PRNGのために、すべてのコードはグローバルな状態を共有します。PRNGの場合,すべてのコードはグローバルな状態を共有します.もしあなたが種を変えたり,PRNGの状態を変えたりすると,その影響は予想以上に大きくなるかもしれません.

しかし、プログラムはこのメソッドの結果がランダムであることを期待しているので(それが目的なので)、これは決して問題にはならないかもしれません。プログラムが期待した数値の並びを見ることができるのは、定数値でsrandを呼び出したときなど、予期しない結果を見ることになる場合だけなのです。