これは、私が最近参加したインタビューの1つで尋ねられた質問でした。
私の知る限り、2つの数の間の乱数は次のように生成できます。
public static int Rand(int low, int high) {
return low + (int)(Math.random() * (high - low + 1));
}
しかし、ここでは、Math.random()を使用して0から1までの乱数を生成し、それを使用して低から高までの乱数を生成しています。外部関数を使用せずに直接実行できる他の方法はありますか?
一般的な疑似乱数ジェネレーターは、以前の数値に基づいて新しい数値を計算するため、理論的には完全に決定論的です。唯一のランダム性は、適切なシード(乱数生成アルゴリズムの初期化)を提供することによって保証されます。乱数がセキュリティ上それほど重要でない限り(これには「実際の」乱数が必要になります)、このような再帰的な乱数ジェネレーターは多くの場合、ニーズを満たします。
シードが提供されると、再帰的な生成は「外部」関数なしで表現できます。この問題を解決するアルゴリズムがいくつかあります。良い例は Linear Congruential Generator です。
擬似コードの実装は次のようになります。
long a = 25214903917; // These Values for a and c are the actual values found
long c = 11; // in the implementation of Java.util.Random(), see link
long previous = 0;
void rseed(long seed) {
previous = seed;
}
long Rand() {
long r = a * previous + c;
// Note: typically, one chooses only a couple of bits of this value, see link
previous = r;
return r;
}
このジェネレータに初期値をシードする必要があります。これは、次のいずれかを実行することで実行できます。
アルゴリズムなしがあり、differentdifferentの値を生成できることに注意してください。同じ入力一部のアクセスなし外部ソースシステム環境のように。よくシードされた乱数ジェネレーターはすべて、いくつかの外部ソースを利用します。
ここで私はコメント付きのいくつかの情報源があなたが役立つと思うかもしれないことを提案しています:
/proc
ファイルデータ:Linuxシステムの場合。これを使うべきだと思います。
/proc/sys/kernel/random:
このディレクトリには、ファイル/dev/random
の操作を制御するさまざまなパラメータが含まれています。
文字特殊ファイル/dev/random
および/dev/urandom
(Linux 1.3.30
以降に存在)は、カーネルの乱数ジェネレーターへのインターフェースを提供します。
このコンマを試してください:
$cat /dev/urandom
そして
$cat /dev/random
このファイルから読み取るファイル読み取り関数を作成できます。
読む(また提案する): / dev/urandomからのランドはログインキーに対して安全ですか?
`
System.currentTimeMillis()
は外部としてカウントされますか?いつでもこれを取得して、最大値でmodを計算できます。
int Rand = (int)(System.currentTimeMillis()%high)+low;
変数のアドレスを使用するか、より多くの変数のアドレスを組み合わせて、より複雑なものを作成することができます...
ロジスティック写像x = 4x(1-x)
から、0
と1
の間の「非合理的」x
で始まるランダム性(実際には混沌とし、完全に均一ではない*)に近づくことができます。
「ランダム性」が表示されますので浮動小数点表現の精度のエッジでの丸め誤差。
(*)スキューが存在することがわかったら、スキューを元に戻すことができます。
現在のシステム時刻を取得できますが、ほとんどの言語の関数も必要になります。
public class randomNumberGenerator {
int generateRandomNumber(int min, int max) {
return (int) ((System.currentTimeMillis() % max) + min);
}
public static void main(String[] args) {
randomNumberGenerator rn = new randomNumberGenerator();
int cv = 0;
int min = 1, max = 4;
Map<Integer, Integer> hmap = new HashMap<Integer, Integer>();
int count = min;
while (count <= max) {
cv = rn.generateRandomNumber(min, max);
if ((hmap.get(cv) == null) && cv >= min && cv <= max) {
System.out.print(cv + ",");
hmap.put(cv, 1);
count++;
}
}
}
}
外部状態の使用が許可されている場合(たとえば、現在のシステム時刻で長い初期化)、外部関数なしでそれを行うことができます。これは、単純な疑似乱数ジェネレーターを実装するのに十分です。
ランダム関数を呼び出すたびに、状態を使用して新しいランダム値を作成し、状態を更新して、後続の呼び出しで異なる結果が得られるようにします。
これは、通常のJava算術演算やビット演算、あるいはその両方で実行できるため、外部関数は必要ありません。