Java Language
乱数生成
サーチ…
備考
本当にランダムなものは何もないので、javadocはこれらの数値を疑似乱数と呼びます。これらの数値は擬似乱数ジェネレータで生成されます。
疑似乱数
Javaはutils
パッケージの一部として、適切にRandom
という名前の基本擬似乱数ジェネレータを提供します。このオブジェクトは、任意の組込み数値データ型( int
、 float
など)として疑似乱数値を生成するために使用できます。また、これを使用して、ランダムなブール値、またはランダムなバイト配列を生成することもできます。使用例は次のとおりです。
import java.util.Random;
...
Random random = new Random();
int randInt = random.nextInt();
long randLong = random.nextLong();
double randDouble = random.nextDouble(); //This returns a value between 0.0 and 1.0
float randFloat = random.nextFloat(); //Same as nextDouble
byte[] randBytes = new byte[16];
random.nextBytes(randBytes); //nextBytes takes a user-supplied byte array, and fills it with random bytes. It returns nothing.
注:このクラスは、かなり低品質の擬似乱数しか生成しません。暗号演算などの乱数生成には使用しないでください。高品質のランダム性が重要な場合は、 SecureRandom
クラスを使用します。以下に述べるように)。 「安全」と「安全でない」ランダム性の区別についての説明は、この例の範囲外です。
特定範囲の疑似乱数
Random
nextInt(int bound)
メソッドは、上位の排他的境界、つまり返される乱数値がより小さい数を受け取ります。ただし、 nextInt
メソッドだけがバインドを受け入れます。 nextLong
、 nextDouble
などしないでください。
Random random = new Random();
random.nextInt(1000); // 0 - 999
int number = 10 + random.nextInt(100); // number is in the range of 10 to 109
Java 1.7 ThreadLocalRandom
( source )を使用することもできます。このクラスは、スレッドセーフPRNG(擬似乱数ジェネレータ)を提供します。このクラスのnextInt
メソッドは、上限と下限の両方を受け入れることに注意してください。
import java.util.concurrent.ThreadLocalRandom;
// nextInt is normally exclusive of the top value,
// so add 1 to make it inclusive
ThreadLocalRandom.current().nextInt(min, max + 1);
公式文書では、 bound
が2 30 +1(emphasis added)に近い場合、 nextInt(int bound)
は変なことを行うことができることに注意してください。
アルゴリズムはややこしい。 これは、 (2 ^ 31がnで割り切れないという事実のために) 不均一な分布をもたらす値を拒絶する 。値が拒絶される確率はnに依存する。 最悪のケースは、n = 2 ^ 30 + 1であり、それに対して、拒絶の確率は1/2であり、ループ終了前の予想反復回数は2である。
つまり、バインディングを指定するとnextInt
メソッドのパフォーマンスが低下しますが、このパフォーマンスの低下は、 bound
がmax int値の半分に近づくほど顕著になります。
暗号的に安全な擬似乱数の生成
Random
とThreadLocalRandom
は、日々の使用には十分ですが、大きな問題があります。 線形合同ジェネレータは、出力がかなり簡単に予測できるアルゴリズムです。したがって、これらの2つのクラスは、暗号の使用(キー生成など)には適していません 。
予測が非常に困難なPRNGが必要な状況でjava.security.SecureRandom
を使用することができます。このクラスのインスタンスによって作成された乱数を予測することは、クラスを暗号的に安全なものとしてラベル付けするほど難しいです。
import java.security.SecureRandom;
import java.util.Arrays;
public class Foo {
public static void main(String[] args) {
SecureRandom rng = new SecureRandom();
byte[] randomBytes = new byte[64];
rng.nextBytes(randomBytes); // Fills randomBytes with random bytes (duh)
System.out.println(Arrays.toString(randomBytes));
}
}
SecureRandom
は、暗号的に安全であることに加えて、2 48の Random
期間と比較して、2 160という巨大な期間を持っています。これは、よりかなり遅いことの一つの欠点があるRandom
とのような他の線形のPRNG メルセンヌツイスターとXorshiftをしかし、。
SecureRandom実装は、プラットフォームとプロバイダの両方に依存します。デフォルトのSecureRandom
( sun.security.provider.SecureRandom
SUN
プロバイダによって指定されsun.security.provider.SecureRandom
):
- Unixのようなシステムでは、
/dev/random
や/dev/urandom
からのデータがシードされています。 - Windowsでは、 CryptoAPIの
CryptGenRandom()
呼び出しがシードされています。
重複のない乱数を選択する
/**
* returns a array of random numbers with no duplicates
* @param range the range of possible numbers for ex. if 100 then it can be anywhere from 1-100
* @param length the length of the array of random numbers
* @return array of random numbers with no duplicates.
*/
public static int[] getRandomNumbersWithNoDuplicates(int range, int length){
if (length<range){
// this is where all the random numbers
int[] randomNumbers = new int[length];
// loop through all the random numbers to set them
for (int q = 0; q < randomNumbers.length; q++){
// get the remaining possible numbers
int remainingNumbers = range-q;
// get a new random number from the remainingNumbers
int newRandSpot = (int) (Math.random()*remainingNumbers);
newRandSpot++;
// loop through all the possible numbers
for (int t = 1; t < range+1; t++){
// check to see if this number has already been taken
boolean taken = false;
for (int number : randomNumbers){
if (t==number){
taken = true;
break;
}
}
// if it hasnt been taken then remove one from the spots
if (!taken){
newRandSpot--;
// if we have gone though all the spots then set the value
if (newRandSpot==0){
randomNumbers[q] = t;
}
}
}
}
return randomNumbers;
} else {
// invalid can't have a length larger then the range of possible numbers
}
return null;
}
このメソッドは、要求された長さのサイズを持つ配列をループし、残りの長さを見つけることによって機能します。これらの可能な番号の乱数をnewRandSpot
に設定し、その番号を未取得の数の中に見つけます。これは、範囲をループし、その番号がすでに取得されているかどうかを確認することによってこれを行います。
たとえば、範囲が5で長さが3で、すでに2を選択している場合は残りの4つの数字があるので、1と4の間の乱数を取得し、任意の数をスキップする範囲(5)をループします私たちはすでに使用しています(2)。
今度は、1と4の間で選択された次の数字が3であるとしましょう。最初のループでは、まだ取り出されていない1が得られます。3から1を取り除くことができます。2.今度は2番目のループで、私たちは何もしません。私たちは4になるまでこのパターンに従います.1を削除すると0になりますので、新しいrandomNumberを4に設定します。
指定されたシードで乱数を生成する
//Creates a Random instance with a seed of 12345.
Random random = new Random(12345L);
//Gets a ThreadLocalRandom instance
ThreadLocalRandom tlr = ThreadLocalRandom.current();
//Set the instance's seed.
tlr.setSeed(12345L);
同じシードを使用して乱数を生成すると、毎回同じ数値が返されるため、重複した数字になりたくない場合は、すべてのRandom
インスタンスに対して異なるシードを設定することをお勧めします。
すべての呼び出しで異なるLong
を取得する良い方法は、 System.currentTimeMillis()
です。
Random random = new Random(System.currentTimeMillis());
ThreadLocalRandom.current().setSeed(System.currentTimeMillis());
apache-common lang3を使って乱数を生成する
org.apache.commons.lang3.RandomUtils
を使用して、1行で乱数を生成することができます。
int x = RandomUtils.nextInt(1, 1000);
nextInt(int startInclusive, int endExclusive)
メソッドは範囲をとります。
intとは別に、このクラスを使用してlong
、 double
、 float
およびbytes
をランダムに生成できbytes
。
RandomUtils
クラスには次のメソッドが含まれています。
static byte[] nextBytes(int count) //Creates an array of random bytes.
static double nextDouble() //Returns a random double within 0 - Double.MAX_VALUE
static double nextDouble(double startInclusive, double endInclusive) //Returns a random double within the specified range.
static float nextFloat() //Returns a random float within 0 - Float.MAX_VALUE
static float nextFloat(float startInclusive, float endInclusive) //Returns a random float within the specified range.
static int nextInt() //Returns a random int within 0 - Integer.MAX_VALUE
static int nextInt(int startInclusive, int endExclusive) //Returns a random integer within the specified range.
static long nextLong() //Returns a random long within 0 - Long.MAX_VALUE
static long nextLong(long startInclusive, long endExclusive) //Returns a random long within the specified range.