How do I generate random integers within a specific range in Java?

Как создать случайный 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`.

79 ответов

В 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 для выполнения задачи.

Обратите внимание, что этот подход является более предвзятым и менее эффективным, чем nextInt подход, /questions/34217245/mathrandom-i-randomnextintint/34217250#34217250

Один стандартный шаблон для достижения этой цели:

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

Функция библиотеки Java Math Math.random() генерирует двойное значение в диапазоне [0,1), Обратите внимание, что этот диапазон не включает 1.

Чтобы сначала получить определенный диапазон значений, необходимо умножить его на величину диапазона значений, который вы хотите охватить.

Math.random() * ( Max - Min )

Это возвращает значение в диапазоне [0,Max-Min)где "Макс-Мин" не включен.

Например, если вы хотите [5,10), вам нужно покрыть пять целочисленных значений, чтобы вы использовали

Math.random() * 5

Это вернет значение в диапазоне [0,5)где 5 не входит.

Теперь вам нужно сместить этот диапазон до диапазона, на который вы нацеливаетесь. Вы делаете это, добавляя значение Min.

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

Использование:

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

Целое число x теперь случайное число, которое имеет возможный результат 5-10,

Использование:

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

С Java-8 они ввели метод ints(int randomNumberOrigin, int randomNumberBound) в Random учебный класс.

Например, если вы хотите сгенерировать пять случайных целых (или одно) в диапазоне [0, 10], просто выполните:

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 ценности.

Надеюсь, поможет!:)

Вы можете отредактировать ваш второй пример кода:

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

Достаточно небольшой модификации вашего первого решения.

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

Смотрите больше здесь для реализации Random

ThreadLocalRandom эквивалент класса java.util.Random для многопоточной среды. Генерация случайного числа осуществляется локально в каждом из потоков. Таким образом, мы имеем лучшую производительность за счет уменьшения конфликтов.

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

x, y - интервалы, например (1,10)

Math.Random класс в Java основан на 0 Итак, если вы напишите что-то вроде этого:

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

x будет между 0-9 включительно.

Итак, учитывая следующий массив 25 элементы, код для генерации случайного числа между 0 (база массива) и array.length было бы:

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

index = rand.nextInt( i.length );

поскольку i.length вернусь 25, nextInt( i.length ) вернет число в диапазоне 0-24, Другой вариант идет с Math.Random который работает таким же образом.

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

Для лучшего понимания, проверьте сообщение на форуме Случайные интервалы (archive.org).

Если вы хотите попробовать ответ с большинством голосов выше, вы можете просто использовать этот код:

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 отрицательно.

Надежное решение вернет правильные результаты для любого min <= max в [Integer.MIN_VALUE, Integer.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% или выше.

Интересно, подойдет ли какой-либо из методов генерации случайных чисел, предоставляемых библиотекой Apache Commons Math.

Например: RandomDataGenerator.nextInt или же RandomDataGenerator.nextLong

Я использую это:

 /**
   * @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;
 }

Вы можете привести его к Integer, если хотите. Надеюсь, поможет:)

Начиная с Java 7, вы больше не должны использовать Random, Для большинства случаев выбор генератора случайных чисел теперь ThreadLocalRandom,

Для пулов вилки и параллельных потоков используйтеSplittableRandom,

Джошуа Блох.Эффективная Java.Третье издание.

Начиная с 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);
 rand.nextInt((max+1) - min) + min;

Давайте возьмем пример.

Предположим, я хочу сгенерировать число от 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);

Дайте нам понять это...

Инициализируйте max с самым высоким значением и 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

Отсюда получаем желаемый диапазон.

Сгенерируйте случайное число для разницы min и max с помощью метода nextint(n), а затем добавьте минимальное число к результату:

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

Просто используйте класс 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;
}

Для генерации случайного числа "между двумя числами" используйте следующий код:

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 вместо 10.

В случае броска костей это будет случайное число от 1 до 6 (не от 0 до 6), поэтому:

face = 1 + randomNumbers.nextInt(6);
int random = minimum + Double.valueOf(Math.random()*(maximum-minimum )).intValue();

Или взгляните на RandomUtils от Apache Commons.

Вот полезный класс для генерации случайных 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;
    }
}

Вы можете достичь этого кратко в 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);

Другой вариант - просто использовать 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);
    // ...
 }
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);
}

Я нашел этот пример Генерация случайных чисел:


В этом примере генерируются случайные целые числа в определенном диапазоне.

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.

Лучше использовать SecureRandom, чем просто Random.

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

Вот простой пример, который показывает, как генерировать случайное число из закрытых [min, max] диапазон, в то время как min <= max is true

Вы можете использовать его как поле в классе отверстия, также имея все Random.class методы в одном месте

Пример результатов:

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

Когда вам нужно много случайных чисел, я не рекомендую случайный класс в API. У него слишком маленький период. Попробуйте вместо этого твистер Мерсенна. Есть реализация Java.

Другие вопросы по тегам