重複 Javaの特定の範囲内でランダム整数を生成する方法は?




java 乱数 重複 (24)

rand.nextInt((max+1) - min) + min;

これはうまくいきます。

特定の範囲でランダムなint値を生成するにはどうすればよいですか?

私は以下を試しましたが、それらはうまくいきません:

試行1:

randomNum = minimum + (int)(Math.random() * maximum);
// Bug: `randomNum` can be bigger than `maximum`.

試行2:

Random rn = new Random();
int n = maximum - minimum + 1;
int i = rn.nextInt() % n;
randomNum =  minimum + i;
// Bug: `randomNum` can be smaller than `minimum`.

もう一つの選択肢はApache Commonsを使うことです:

import org.apache.commons.math.random.RandomData;
import org.apache.commons.math.random.RandomDataImpl;

public void method() {
    RandomData randomData = new RandomDataImpl();
    int number = randomData.nextInt(5, 10);
    // ...
 }

Java 1.7以降では、これを行う標準的な方法は次のとおりです。

import java.util.concurrent.ThreadLocalRandom;

// nextInt is normally exclusive of the top value,
// so add 1 to make it inclusive
int randomNum = ThreadLocalRandom.current().nextInt(min, max + 1);

関連するJavaDocを参照してください。 このアプローチには、 java.util.Randomインスタンスを明示的に初期化する必要がないという利点があります。これは、不適切に使用されると混乱やエラーの原因となる可能性があります。

しかし、逆に、シードを明示的に設定する方法がないため、テストやゲームの状態の保存などの有用な状況で結果を再現するのが難しい場合があります。 このような状況では、以下に示すJava 1.7より前の手法を使用できます。

Java 1.7より前のバージョンでは、これを行うための標準的な方法は次のとおりです。

import java.util.Random;

/**
 * Returns a pseudo-random number between min and max, inclusive.
 * The difference between min and max can be at most
 * <code>Integer.MAX_VALUE - 1</code>.
 *
 * @param min Minimum value
 * @param max Maximum value.  Must be greater than min.
 * @return Integer between min and max, inclusive.
 * @see java.util.Random#nextInt(int)
 */
public static int randInt(int min, int max) {

    // NOTE: This will (intentionally) not run as written so that folks
    // copy-pasting have to think about how to initialize their
    // Random instance.  Initialization of the Random instance is outside
    // the main scope of the question, but some decent options are to have
    // a field that is initialized once and then re-used as needed or to
    // use ThreadLocalRandom (if using at least Java 1.7).
    // 
    // In particular, do NOT do 'Random rand = new Random()' here or you
    // will get not very good / not very random results.
    Random rand;

    // nextInt is normally exclusive of the top value,
    // so add 1 to make it inclusive
    int randomNum = rand.nextInt((max - min) + 1) + min;

    return randomNum;
}

関連するJavaDocを参照してください。 実際には、 java.util.Randomクラスはjava.lang.Math.random()よりもよく使用されることがよくありjava.lang.Math.random()

特に、タスクを達成するために標準ライブラリ内に簡単なAPIがある場合、ランダム整数生成ホイールを再作成する必要はありません。


インクルーシブ/排他的な範囲の任意の組み合わせで範囲内のランダムなintsを生成するのに役立つクラスは次のとおりです。

import java.util.Random;

public class RandomRange extends Random {
    public int nextIncInc(int min, int max) {
        return nextInt(max - min + 1) + min;
    }

    public int nextExcInc(int min, int max) {
        return nextInt(max - min) + 1 + min;
    }

    public int nextExcExc(int min, int max) {
        return nextInt(max - min - 1) + 1 + min;
    }

    public int nextIncExc(int min, int max) {
        return nextInt(max - min) + min;
    }
}

上の投票で答えを試したいのであれば、単にこのコードを使うことができます:

public class Randomizer
{
    public static int generate(int min,int max)
    {
        return min + (int)(Math.random() * ((max - min) + 1));
    }

    public static void main(String[] args)
    {
        System.out.println(Randomizer.generate(0,10));
    }
}

それはきれいでシンプルです。


私が慎重であることを許してください。しかし、大多数が提案した解決策、すなわちmin + rng.nextInt(max - min + 1))

  • rng.nextInt(n)Integer.MAX_VALUE到達できません。
  • (max - min)は、 minが負の場合にオーバーフローを引き起こす可能性があります。

簡単な解決法は、[ Integer.MIN_VALUEInteger.MAX_VALUE ]内の任意のmin <= maxに対して正しい結果を返すでしょう。 以下の単純な実装を考えてみましょう。

int nextIntInRange(int min, int max, Random rng) {
   if (min > max) {
      throw new IllegalArgumentException("Cannot draw random int from invalid range [" + min + ", " + max + "].");
   }
   int diff = max - min;
   if (diff >= 0 && diff != Integer.MAX_VALUE) {
      return (min + rng.nextInt(diff + 1));
   }
   int i;
   do {
      i = rng.nextInt();
   } while (i < min || i > max);
   return i;
}

非効率的ですが、 whileループの成功確率は常に50%以上になることに注意してください。


java-8では、 ints(int randomNumberOrigin, int randomNumberBound)のメソッドをRandomクラスに導入しました。

たとえば、[0、10]の範囲に5つの乱数(または1つ)を生成する場合は、次のようにします。

Random r = new Random();
int[] fiveRandomNumbers = r.ints(5, 0, 11).toArray();
int randomNumber = r.ints(1, 0, 11).findFirst().getAsInt();

最初のパラメータは、生成されたIntStreamのサイズを示します(これは、無制限のIntStreamを生成するオーバーロードされたメソッドです)。

複数の別々の呼び出しを行う必要がある場合は、ストリームから無限プリミティブイテレータを作成できます。

public final class IntRandomNumberGenerator {

    private PrimitiveIterator.OfInt randomIterator;

    /**
     * Initialize a new random number generator that generates
     * random numbers in the range [min, max]
     * @param min - the min value (inclusive)
     * @param max - the max value (inclusive)
     */
    public IntRandomNumberGenerator(int min, int max) {
        randomIterator = new Random().ints(min, max + 1).iterator();
    }

    /**
     * Returns a random number in the range (min, max)
     * @return a random number in the range (min, max)
     */
    public int nextInt() {
        return randomIterator.nextInt();
    }
}

double値とlong値についても行うことができます。

それが役に立てば幸い! :)


Java 7以降、 Random使用しないでください。 ほとんどの用途では、選択した乱数ジェネレータがThreadLocalRandom

フォーク結合プールと並列ストリームの場合、 SplittableRandom使用しSplittableRandom

ジョシュア・ブロッホ。 効果的なJava。 第3版。

Java 8から始める

フォーク結合プールと並列ストリームの場合、通常は高速のSplittableRandomを使用し、 Randomと比較してより優れた統計的独立性と均一性プロパティを持ちます。

範囲[0, 1_000]:ランダムなintを生成するには[0, 1_000]:

int n = new SplittableRandom().nextInt(0, 1_001);

[0, 1_000]:範囲の値のランダムなint[100]配列を生成するには[0, 1_000]:

int[] a = new SplittableRandom().ints(100, 0, 1_001).parallel().toArray();

ランダム値のストリームを返すには:

IntStream stream = new SplittableRandom().ints(100, 0, 1_001);

あなたはJava 8でそれを簡潔に達成することができます:

Random random = new Random();

int max = 10;
int min = 5;
int totalNumber = 10;

IntStream stream = random.ints(totalNumber, min, max);
stream.forEach(System.out::println);

サイコロを振る場合、1から6までの乱数(0から6までではない)があります:

face = 1 + randomNumbers.nextInt(6);

ここでは、閉じた[min, max]範囲から乱数を生成する方法を示す簡単なサンプルを示しますが、 min <= max is true

ホールクラスのフィールドとして再利用することができます。また、すべてのRandom.classメソッドを1つの場所に持つこともできます

結果の例:

RandomUtils random = new RandomUtils();
random.nextInt(0, 0); // returns 0
random.nextInt(10, 10); // returns 10
random.nextInt(-10, 10); // returns numbers from -10 to 10 (-10, -9....9, 10)
random.nextInt(10, -10); // throws assert

ソース:

import junit.framework.Assert;
import java.util.Random;

public class RandomUtils extends Random {

    /**
     * @param min generated value. Can't be > then max
     * @param max generated value
     * @return values in closed range [min, max].
     */
    public int nextInt(int min, int max) {
        Assert.assertFalse("min can't be > then max; values:[" + min + ", " + max + "]", min > max);
        if (min == max) {
            return max;
        }

        return nextInt(max - min + 1) + min;
    }
}

public static Random RANDOM = new Random(System.nanoTime());

public static final float random(final float pMin, final float pMax) {
    return pMin + RANDOM.nextFloat() * (pMax - pMin);
}

ランダムではなくSecureRandomを使用する方が良いでしょう。

public static int generateRandomInteger(int min, int max) {
    SecureRandom rand = new SecureRandom();
    rand.setSeed(new Date().getTime());
    int randomNum = rand.nextInt((max - min) + 1) + min;
    return randomNum;
}

つかいます:

Random ran = new Random();
int x = ran.nextInt(6) + 5;

整数xは現在、 5-10結果が得られる乱数になります。


private static Random random = new Random();    

public static int getRandomInt(int min, int max){
  return random.nextInt(max - min + 1) + min;
}

または

public static int getRandomInt(Random random, int min, int max)
{
  return random.nextInt(max - min + 1) + min;
}

つかいます:

minimum + rn.nextInt(maxValue - minvalue + 1)


例を挙げてみましょう。

5-10の間の数値を生成したいとします。

int max = 10;
int min = 5;
int diff = max - min;
Random rn = new Random();
int i = rn.nextInt(diff + 1);
i += min;
System.out.print("The Random Number is " + i);

これを理解してみましょう ...

最高値でminを初期化し、最低値でminを初期化します。

さて、得られる可能な値の数を決定する必要があります。 この例では、次のようになります。

5,6,7,8,9,10

したがって、この数は最大 - 最小+1になります。

すなわち10 -5 + 1 = 6

乱数は0〜5の間の数値を生成します。

すなわち、0,1,2,3,4,5

乱数に最小値を加えると次のようになります:

5,6,7,8,9,10

したがって、我々は所望の範囲を得る。


ただRandomクラスを使用してください:

Random ran = new Random();
// Assumes max and min are non-negative.
int randomInt = min + ran.nextInt(max - min + 1);

このメソッドは便利です:

このメソッドは、指定さた最小値と最大値のの乱数を返します。

public static int getRandomNumberBetween(int min, int max) {
    Random foo = new Random();
    int randomNumber = foo.nextInt(max - min) + min;
    if (randomNumber == min) {
        // Since the random number is between the min and max values, simply add 1
        return min + 1;
    } else {
        return randomNumber;
    }
}

このメソッドは指定さた最小値と最大値から乱数を返します(生成された数値も最小値または最大値になる可能性があります)。

public static int getRandomNumberFrom(int min, int max) {
    Random foo = new Random();
    int randomNumber = foo.nextInt((max + 1) - min) + min;

    return randomNumber;
}

nextint(n)メソッドを使用してminとmaxの差の乱数を生成し、minの数値を結果に追加します。

Random rn = new Random();
int result = rn.nextInt(max - min + 1) + min;
System.out.println(result);

int random = minimum + Double.valueOf(Math.random()*(maximum-minimun)).intValue();

あるいは、 Apache Commonsの RandomUtilsを見てください。


 rand.nextInt((max+1) - min) + min;

あなたの最初の解決策のほんの少しの変更で十分でしょう。

Random rand = new Random();
randomNum = minimum + rand.nextInt((maximum - minimum) + 1);

Random実装の詳細はこちら





integer