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

2008年12月13日に質問されました。  ·  閲覧回数 4.2M回  ·  ソース

user42155 picture
2008年12月13日

特定の範囲でランダムな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`.

回答

Greg Case picture
2008年12月13日
3908

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インスタンスを明示的に初期化する必要がないという利点があります。これは、不適切に使用すると混乱やエラーの原因となる可能性があります。

ただし、逆にシードを明示的に設定する方法がないため、ゲームの状態のテストや保存など、それが役立つ状況では結果を再現することが難しい場合があります。 このような状況では、以下に示すJava1.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()よりも望ましいことがよくあり

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

TJ_Fischer picture
2008年12月13日
1442

このアプローチは、 nextIntアプローチよりも偏りがあり、効率が低いことに注意してください。https://stackoverflow.com/a/738651/360211

これを実現するための1つの標準パターンは次のとおりです。

Min + (int)(Math.random() * ((Max - Min) + 1))

Java Mathライブラリ関数Math.random()は、 [0,1)範囲のdouble値を生成します。 この範囲には1が含まれていないことに注意してください。

最初に特定の値の範囲を取得するには、カバーする値の範囲の大きさを掛ける必要があります。

Math.random() * ( Max - Min )

これは、 [0,Max-Min)の範囲の値を返します。ここで、「Max-Min」は含まれていません。

たとえば、 [5,10)が必要な場合は、5つの整数値をカバーする必要があるため、

Math.random() * 5

これにより、 [0,5)範囲の値が返されます。ここで、5は含まれていません。

次に、この範囲をターゲットの範囲までシフトする必要があります。 これを行うには、最小値を追加します。

Min + (Math.random() * (Max - Min))

これで、 [Min,Max)範囲の値が得られます。 私たちの例に従うと、それは[5,10)を意味します:

5 + (Math.random() * (10 - 5))

ただし、これにはまだMax含まれておらず、2倍の値が得られます。 Max値を含めるには、範囲パラメーター(Max - Min) 1を追加してから、intにキャストして小数部を切り捨てる必要があります。 これは、次の方法で実行されます。

Min + (int)(Math.random() * ((Max - Min) + 1))

そして、あなたはそれを持っています。 [Min,Max]の範囲のランダムな整数値、または例では[5,10]

5 + (int)(Math.random() * ((10 - 5) + 1))
jackson picture
2009年09月04日
393

使用する:

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

整数xは、 5-10結果が得られる可能性のある乱数になりました。

krosenvold picture
2008年12月13日
165

使用する:

minimum + rn.nextInt(maxValue - minvalue + 1)
Alexis C. picture
2014年11月27日
154

、彼らはRandomクラスにメソッドints(int randomNumberOrigin, int randomNumberBound)を導入しました。

たとえば、[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値に対しても実行できます。 お役に立てば幸いです。 :)

Bill the Lizard picture
2008年12月13日
109

2番目のコード例を次のように編集できます。

Random rn = new Random();
int range = maximum - minimum + 1;
int randomNum =  rn.nextInt(range) + minimum;
hexabunny picture
2015年03月13日
102

最初のソリューションを少し変更するだけで十分です。

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

Random実装については、こちらをご覧ください

andrew picture
2013年02月13日
84

マルチスレッド環境のクラスjava.util.Randomに相当するThreadLocalRandom 。 乱数の生成は、各スレッドでローカルに実行されます。 したがって、競合を減らすことでパフォーマンスが向上します。

int rand = ThreadLocalRandom.current().nextInt(x,y);

xy -間隔(例:(1,10))

Matt R picture
2009年01月08日
71

JavaMath.Randomクラスは0ベースです。 したがって、次のように書くと、次のようになります。

Random rand = new Random();
int x = rand.nextInt(10);

x0-9間になります。

したがって、次の25アイテムの配列が与えられた場合、 0 (配列のベース)とarray.length間の乱数を生成するコードは次のようになります。

String[] i = new String[25];
Random rand = new Random();
int index = 0;

index = rand.nextInt( i.length );

i.length25 nextInt( i.length )を返すため、 0-24範囲の数値を返します。 もう1つのオプションは、同じように機能するMath.Randomを使用することです。

index = (int) Math.floor(Math.random() * i.length);

理解を深めるには、フォーラムの投稿Random Intervals(archive.org)を確認してください。

Joel Sj&#246;strand picture
2011年01月10日
50

気難しいことを許してください。しかし、大多数が提案した解決策、つまりmin + rng.nextInt(max - min + 1)) 、次の事実のために危険なようです。

  • rng.nextInt(n)Integer.MAX_VALUE到達できません。
  • (max - min) minが負の場合、 (max - 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%以上になることに注意してください。