Питання Як створити випадкові цілі числа в межах певного діапазону в 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`.

2903
2017-12-12 18:20


походження




Відповіді:


В 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. Цей підхід має перевагу у тому, що не потрібно явним чином ініціалізувати a 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 для виконання завдання.


3260
2017-12-12 18:25



Для дзвінків де max цінність є Integer.MAX_VALUE це можливо переповнення, що приводить до а java.lang.IllegalArgumentException. Ви можете спробувати з: randInt(0, Integer.MAX_VALUE). Крім того, якщо nextInt((max-min) + 1) повертає найвище значення (досить рідко, я вважаю), чи не переповнюється це знову (припускаючи, що min та max є досить високими значеннями)? Як боротися з подібними ситуаціями? - Daniel
Це не працює для довгих - momo
@MoisheLipsker Мабуть, the nextLong не береться за nextInteger - momo
@ лелентов ThreadLocalRandom був доданий до Java 2 через півтора року після того, як це питання було задано спочатку. Я завжди був твердою думкою, що управління випадковим прикладом виходить за межі питання. - Greg Case
У Android Random rand = new Random (); - Webserveis


Зауважте, що цей підхід є більш упередженим та менш ефективним, ніж a nextInt підхід https://stackoverflow.com/a/738651/360211

Одним з еталонів для досягнення цієї мети є:

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

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

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

Math.random() * ( Max - Min )

Це повертає значення в діапазоні [0,Max-Min), де "Max-Min" не входить.

Наприклад, якщо хочете [5,10), вам потрібно покрити п'ять цілих значень, які ви використовуєте

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

1324
2017-12-12 18:35



Документація Сонця чітко говорить, що краще використовувати Random (), якщо вам потрібен int замість Math.random (), який створює подвійне значення. - Lilian A. Moraru
Це фактично упередженим у порівнянні з наступними методами stackoverflow.com/a/738651/360211 - weston


Використання:

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

Ціле число x тепер це випадкове число, яке має можливий результат 5-10.


311
2017-09-04 04:23





Використання:

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

122
2017-12-12 18:25





З  вони представили метод 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 цінності

Сподіваюся, це допоможе! :)


99
2017-11-26 18:29



Я б запропонував вам інстанціювати randomIterator лише один раз. Див. Гріг Кейс, коментуючи власну відповідь. - Naxos84
якщо ви можете, чи можете ви пояснити, наскільки це важливо streamSize - дано перший параметр даного методу streamSize !=0. Яка різниця, якщо streamSize 1/2 / n дано? - Erfan Ahmed Emon
Солодке рішення, особливо клас потоку. - cen


Ви можете редагувати свій другий приклад коду, щоб:

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

90
2017-12-12 18:31





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

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

Дивіться більше тут для реалізації Random


89
2018-03-12 22:44



Для мінімального <= значення <максимум, я зробив те ж саме з математикою: randomNum = мінімальний + (int) (Math.random () * (максимальний-мінімальний)); але кастинг не дуже приємно бачити;) - AxelH


ThreadLocalRandom еквівалент класу java.util.Random для багатопотокового середовища. Генерування випадкового числа виконується локально в кожному з потоків. Отже, ми маємо кращу продуктивність, скорочуючи конфлікти.

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

x, y - інтервали, наприклад (1,10)


54
2018-02-12 23:19



Заради Бога ця відповідь повинна бути прийнята. Дивись також Чи є підстави писати? new Random() починаючи з Java 8? - leventov
@leventov це не може бути прийнятою відповіддю, ця реалізація підтримується тільки => LOLLIPOP - Relm
Деякий час для людей треба розвивати «Ляльопоп», якщо не робити цього, просто затягує ринок. Зробіть, щоб ваші програми підтримували нові API, щоб змусити перевізників оновлюватися. - Martin Marconcini