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


3507

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`.

たくさんの乱数が必要な場合、APIのRandomクラスはお勧めしません。期間が短すぎます。代わりにメルセンヌツイスターをお試しください。Javaの実装あります
raupach 2008

1
新しい回答を投稿する前に、この質問にはすでに65以上の回答があることを考慮してください。回答が既存の回答に含まれない情報を提供していることを確認してください。
janniks

回答:


3801

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()よりも望ましい場合がよくあります

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


43
max値がInteger.MAX_VALUEである呼び出しの場合、オーバーフローしてになる可能性がありますjava.lang.IllegalArgumentException。:で試すことができますrandInt(0, Integer.MAX_VALUE)。また、nextInt((max-min) + 1)最も高い値を返す場合(非常にまれだと思います)、再びオーバーフローしませんか(minとmaxが十分に高い値であると想定)。このような状況にどう対処するか?
ダニエル

3
@MoisheLipskerそれは、nextLongがnextIntegerとして限界をとらないということでなければなりません
mmm

13
@leventov ThreadLocalRandomは、この質問が最初に尋ねられてから2年半後にJavaに追加されました。私は常に、ランダムなインスタンスの管理は問題の範囲外であるという固い意見を持っています。
グレッグケース

6
AndroidではRandom rand = new Random();
Webserveis

5
@Webserveisこれは、例のコメントで対処されています。ショートバージョン-関数を呼び出すたびに=新しいRandom()を使用しないでください。そうしないと、多くの場合、結果がランダムになりません。
グレッグケース

1422

このアプローチはnextInthttps://stackoverflow.com/a/738651/360211のアプローチよりもバイアスがかかり効率が悪いことに注意してください。

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

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

Javaの数学ライブラリ関数Math.random()の範囲内のdouble値を生成します[0,1)。この範囲には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、二重の値を取得しています。Max含まれる値を取得するには、範囲パラメーターに1を追加して(Max - Min)から、intにキャストして小数部を切り捨てる必要があります。これは、以下を介して実行されます。

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

そして、そこにあります。範囲内[Min,Max]、または例ごとのランダムな整数値[5,10]

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

82
Sunのドキュメントでは、doubleを生成するMath.random()の代わりにintが必要な場合は、Random()を使用するほうがよいと明確に述べています。
リリアンA.モラル

6
これは、実際にnextIntの方法に比べてバイアスされているstackoverflow.com/a/738651/360211
ウェストン

4
この場合の「バイアス」とは、2 ^ 53の実行後に、平均していくつかの数値が1つの余分なオキュランスを持っていることを意味します。
頭足類



137

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

たとえば、[0、10]の範囲で5つのランダムな整数(または単一の整数)を生成する場合は、次のようにします。

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

最初のパラメーターは、IntStream生成されたサイズを示します(これは、unlimitedを生成するメソッドのオーバーロードされたメソッドです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値。お役に立てば幸いです。:)


1
randomIteratorを1回だけインスタンス化することをお勧めします。彼自身の答えについては、グレッグ・ケースのコメントをご覧ください。
Naxos84

もしそうなら、あなたはその意味が何であるかを説明できますかstreamSize-このメソッドの最初のパラメータが与えられstreamSize !=0ます。1/2 streamSize/ nが与えられた場合の違いは何ですか?
Erfan Ahmed 2018

104

2番目のコード例を編集して、次のことができます。

Random rn = new Random();
int range = maximum - minimum + 1;
int randomNum =  rn.nextInt(range) + minimum;

100

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

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

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


最小値<=値<最大値の場合、私はMathで同じことを行いました:randomNum = minimum +(int)(Math.random()*(maximum-minimum)); しかし、キャストは見るのは本当に素晴らしいものではありません;)
AxelH

少なくとも7年遅れの重複回答。
Maarten Bodewes

70

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

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

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


66

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.length返され25nextInt( i.length )の範囲の数値を戻します0-24。他のオプションはMath.Random同じように機能します。

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

よりよく理解するために、フォーラムの投稿Random Intervals(archive.org)をチェックしてください。


wayBackMachineアーカイブのスクリーンショットリンクの+1とあなたの答えは、範囲内の「ランダムな」整数を取得するための参照としても役立ちます。
Tapper7

あなたが0にインデックスをインスタンス化し、なぜそれは私をバッフル
AjahnCharles

@CodeConfident index変数は、乱数の結果に影響を与えません。結果の変更を心配することなく、好きな方法で初期化することができます。お役に立てれば。
Matt R

まさに...完全に未使用です。私はランドに直接それを初期化します:int index = rand.nextInt(i.Length);
AjahnCharles

またはまったくない。 int index; \n index = rand...別の行での宣言と割り当てが好きな場合。一部のコーディング標準は、他よりも厳格です(明確な目的はありません)。
Mark Storer

49

潔癖であることのために私を許したが、過半数によって提案された解決策、すなわち、min + rng.nextInt(max - min + 1))、という事実による危険なようです:

  • rng.nextInt(n)届きませんInteger.MAX_VALUE
  • (max - min)minが負の場合、オーバーフローが発生する可能性があります。

フールプルーフソリューションは、min <= max[ Integer.MIN_VALUEInteger.MAX_VALUE] 内のすべてに対して正しい結果を返します。次の素朴な実装を検討してください。

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%以上になることに注意してください。


違いがInteger.MAX_VALUEのときにIllegalArgumentExceptionをスローしないのはなぜですか?その後、whileループは必要ありません。
コルスタンジェ議員、2015年

3
@mpkorstanjeこの実装は、差がMAX_VALUE以上の場合でも、min <= maxの任意の値で機能するように設計されています。成功するまでループを実行することは、この場合の一般的なパターンであり、均一な分布を保証します(ランダム性の基になるソースが均一な場合)。引数が2のべき乗でないときにRandom.nextInt(int)が内部的にそれをしない
クリスチャンSemrau

44

次のステートメントを実行するだけで実行できます。

Randomizer.generate(0,10); //min of zero, max of ten

以下はそのソースコードです

Randomizer.java

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

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


5
これは他の例の編集であった可能性がありますが、今では評判の露骨なコピーにすぎません。「投票数が最も多い回答」を指摘することもあまり直接的ではなく、変わる可能性があります。
Maarten Bodewes 2017年

1
そうです、@ MaartenBodewes。私がこの回答を書いたとき、上記の投票数最も多い回答は、依然としてアルゴリズムのようなソリューションとして書かれていました。さて、上記のソリューションは大幅に変更され、この回答は模倣品のように見えました。
Abel Callejo 2017年

なぜこのような基本的なコードがJava標準ライブラリの一部ではないのか、本当にわかりません。なぜこれを実装する必要があるのですか?
Leevi L


31

例を挙げましょう。

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);

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

最大値で最大値を、最小値で最小値を初期化します。

ここで、取得できる値の数を決定する必要があります。この例では、次のようになります。

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

したがって、目的の範囲を取得します。



26

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

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

26

私はこれを使います:

 /**
   * @param min - The minimum.
   * @param max - The maximum.
   * @return A random double between these numbers (inclusive the minimum and maximum).
   */
 public static double getRandom(double min, double max) {
   return (Math.random() * (max + 1 - min)) + min;
 }

必要に応じて、整数にキャストできます。


この関数は同じ数を繰り返し生成します。私の場合は2147483647
ソクラ

失敗:あなたはdoubleを必要とする関数を持っていて、+ 1を実行しますか?これは確かに最小の驚きの原則に反します。min = 0.1およびmax = 0.2を使用するとどうなりますか?
Maarten Bodewes

@sokrasメソッド呼び出しnew Random(JavaDocをチェック):「新しい乱数ジェネレータを作成します。このコンストラクタは、乱数ジェネレータのシードを、このコンストラクタの他の呼び出しとは異なる可能性が高い値に設定します。」おそらく現在の時刻をシードとして使用するだけの可能性があります。その時間がミリ秒を使用する場合、現在のコンピューターは同じ数を生成するのに十分な速度です。しかし、それ以外に2147483647はInteger.MAX_VALUE; 出力は明らかに、指定していない入力に依存します。
Maarten Bodewes

最終的に実際に機能するものを見つけました
Jency

23

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

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

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

Java 8から

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

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

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

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);

例にが含まれている理由はあり.parallel()ますか?100個の乱数を生成するのは簡単すぎて並列処理を保証できないように思えます。
ジョンボット2018

@ジョンボットコメントありがとうございます。しかし、主な理由はAPIを示すことでした(もちろん、スマートパスはparallel処理を使用する前にパフォーマンスを測定することです)。ちなみに、1_000_000要素の配列の場合、parallelバージョンはシーケンシャルと比較して私のマシンで2倍高速でした。
Oleksandr Pyrohov

21

Randomクラスを使用するだけです。

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

8
以前の無数の投稿に投稿されていなかった新しいものはここにはありません。
Maarten Bodewes 2017年

20

この方法は、使用すると便利な場合があります。

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

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;
}

// Since the random number is between the min and max values, simply add 1。どうして?分はカウントされませんか?通常、範囲は[min、max)で、minが含まれ、maxは除外されます。間違った答え、反対票を投じた。
Maarten Bodewes 2017年

getRandomNumberBetweenは、提供されたエンドポイントを除いた乱数を生成するため、@ MaartenBodewes +1が追加されます。
ルークテイラー

1
min + 1は、他の数の2倍になる可能性がありgetRandomNumberBetweenます。
Lii

19

サイコロを振る場合、1から6の間の乱数になります(0から6ではありません)。

face = 1 + randomNumbers.nextInt(6);

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

または、Apache Commonsの RandomUtilsをご覧ください。


これは便利ですが、小さな欠陥に注意してください。メソッドシグネチャはnextDouble(double startInclusive、double endInclusive)のようになりますが、メソッド内を見ると、endInclusiveは実際にはendExclusiveであるはずです。
zakmck 2015年

Double.valueOf(Math.random()*(maximum-minimun)).intValue()非常に難読化された(そして非効率的な)言い方(int)(Math.random()*(maximum-minimun))です…
Holger

最小リターンのスペルミスマッチ最小+ Double.valueOf(Math.random()*(最大-最小))。intValue();
Hrishikesh Mishra 2016

18

以下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;
    }
}

18

「2つの数値の間」の乱数を生成するには、次のコードを使用します。

Random r = new Random();
int lowerBound = 1;
int upperBound = 11;
int result = r.nextInt(upperBound-lowerBound) + lowerBound;

これにより、1(両端を含む)から11(両端を含まない)までの乱数が得られるため、upperBound値を1を追加して初期化します。たとえば、1から10までの乱数を生成する場合は、upperBound番号を11ではなく11で初期化します。 10。


18

あなたは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);

17
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);
}

16

別のオプションは、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);
    // ...
 }

16

私はこの例を見つけました乱数を生成します


この例では、特定の範囲のランダムな整数を生成します。

import java.util.Random;

/** Generate random integers in a certain range. */
public final class RandomRange {

  public static final void main(String... aArgs){
    log("Generating random integers in the range 1..10.");

    int START = 1;
    int END = 10;
    Random random = new Random();
    for (int idx = 1; idx <= 10; ++idx){
      showRandomInteger(START, END, random);
    }

    log("Done.");
  }

  private static void showRandomInteger(int aStart, int aEnd, Random aRandom){
    if ( aStart > aEnd ) {
      throw new IllegalArgumentException("Start cannot exceed End.");
    }
    //get the range, casting to long to avoid overflow problems
    long range = (long)aEnd - (long)aStart + 1;
    // compute a fraction of the range, 0 <= frac < range
    long fraction = (long)(range * aRandom.nextDouble());
    int randomNumber =  (int)(fraction + aStart);    
    log("Generated : " + randomNumber);
  }

  private static void log(String aMessage){
    System.out.println(aMessage);
  }
} 

このクラスの実行例:

Generating random integers in the range 1..10.
Generated : 9
Generated : 3
Generated : 3
Generated : 9
Generated : 4
Generated : 1
Generated : 3
Generated : 9
Generated : 10
Generated : 10
Done.

14

Randomだけではなく、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;
}

1
同じミリ秒で実行すると同じ数になるので、これはあまり良くありません。メソッドの外側にrand初期化とsetSeetを配置する必要があります。
マラカス2015

はい、シードが必要ですが、SecureRandomを使用します。
grep

申し訳ありませんが、変更リクエストを拒否した人にはJavaプログラミングの手掛かりがありません。これは良い提案ですが、間違いです、同じミリ秒で実行した場合、ランダムではなく同じ数になるのでいます。
マラカス2015

正しい解決策はどこにもありません。静的な初期化ブロックを知っている人は多くありません...これは、シードを設定するために使用する必要があるものです:1:private static int SecureRandom rand = new SecureRandom();2:static { 3:rand.setSeed(...);4:}
maraca

5
シードする必要はまったくありませんSecureRandom。システムによってシードされます。直接呼び出すことsetSeedは非常に危険です。(本当にランダムな)シードを日付に置き換える可能性があります。そして、それは確かになりません AにつながりますSecureRandom、誰もが時間を推測し、試してみて、自分自身のシードできるよう、SecureRandomその情報を使用してインスタンスを。
Maarten Bodewes 2017年

13

これは、閉じた[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;
    }
}

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.