random 乱数 重複 - どのようにJavaで特定の範囲内のランダムな整数を生成するには?




15 Answers

このアプローチは、 nextIntアプローチ( https://stackoverflow.com/a/738651/360211よりも偏っており効率が低いことに注意して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を含んでおらず、あなたは二重価値を得ています。 Max値を取得するには、範囲パラメータ(Max - Min) 1を加え、intにキャストして小数部分を切り捨てる必要があります。 これは次の方法で達成されます。

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

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

5 + (int)(Math.random() * ((10 - 5) + 1))
複数 配列 nextint

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



つかいます:

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



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

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



マルチスレッド環境の場合はjava.util.Randomクラスに相当するThreadLocalRandom 乱数の生成は、各スレッドでローカルに実行されます。 だから私たちは競合を減らしてより良いパフォーマンスを得ています。

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

x、y - 間隔(例えば、1,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%以上になることに注意してください。




例を挙げてみましょう。

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

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




インクルーシブ/排他的な範囲の任意の組み合わせで範囲内のランダムな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;
    }
}



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

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




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

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

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



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

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

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.



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



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



もう一つの選択肢は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);
    // ...
 }



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



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

これはうまくいきます。




Related