Поиск…


замечания

Ничто не является случайным, и поэтому javadoc называет эти числа псевдослучайными. Эти числа создаются с помощью генератора псевдослучайных чисел .

Псевдо-случайные числа

Java предоставляет в составе пакета utils базовый генератор псевдослучайных чисел, который называется « Random . Этот объект может использоваться для генерации псевдослучайного значения как любого из встроенных числовых типов данных ( int , float и т. Д.). Вы также можете использовать его для генерации случайного логического значения или случайного массива байтов. Пример использования:

import java.util.Random;  

...
  
Random random = new Random();
int randInt = random.nextInt();
long randLong = random.nextLong();

double randDouble = random.nextDouble(); //This returns a value between 0.0 and 1.0
float randFloat = random.nextFloat(); //Same as nextDouble

byte[] randBytes = new byte[16];
random.nextBytes(randBytes); //nextBytes takes a user-supplied byte array, and fills it with random bytes. It returns nothing.

ПРИМЕЧАНИЕ. Этот класс производит только низкокачественные псевдослучайные числа и никогда не должен использоваться для генерации случайных чисел для криптографических операций или в других ситуациях, где важна более качественная случайность (для этого вы хотели бы использовать класс SecureRandom , как указано ниже). Объяснение различия между «безопасным» и «неуверенным» случайным образом выходит за рамки этого примера.

Псевдо случайные числа в определенном диапазоне

Метод nextInt(int bound) Random принимает верхнюю эксклюзивную границу, то есть число, которое возвращаемое случайное значение должно быть меньше. Однако только метод nextInt принимает nextInt ; nextLong , nextDouble и т.п. нет.

Random random = new Random();
random.nextInt(1000); // 0 - 999

int number = 10 + random.nextInt(100); // number is in the range of 10 to 109

Начиная с Java 1.7, вы также можете использовать ThreadLocalRandom ( источник ). Этот класс обеспечивает поточно-безопасный PRNG (генератор псевдослучайных чисел). Обратите внимание, что метод nextInt этого класса принимает как верхнюю, так и нижнюю границу.

import java.util.concurrent.ThreadLocalRandom;

// nextInt is normally exclusive of the top value,
// so add 1 to make it inclusive
ThreadLocalRandom.current().nextInt(min, max + 1);

Обратите внимание, что в официальной документации указано, что nextInt(int bound) может делать странные вещи, когда bound около 2 30 +1 (выделено курсивом):

Алгоритм немного сложный. Он отклоняет значения, которые приведут к неравномерному распределению (из-за того, что 2 ^ 31 не делится на n). Вероятность отклонения значения зависит от n. Наихудший случай равен n = 2 ^ 30 + 1, для которого вероятность отклонения равна 1/2, а ожидаемое число итераций до окончания цикла равно 2.

Другими словами, указание границы (немного) уменьшит производительность метода nextInt , и это снижение производительности станет более выраженным, так как bound приближается к половине максимального значения int.

Создание криптографически безопасных псевдослучайных чисел

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

Можно использовать java.security.SecureRandom в ситуациях, когда требуется PRNG с java.security.SecureRandom который очень трудно предсказать. Предсказание случайных чисел, созданных экземплярами этого класса, достаточно сложно, чтобы обозначить класс как криптографически безопасный .

import java.security.SecureRandom;
import java.util.Arrays;

public class Foo {
    public static void main(String[] args) {
        SecureRandom rng = new SecureRandom();
        byte[] randomBytes = new byte[64];
        rng.nextBytes(randomBytes); // Fills randomBytes with random bytes (duh)
        System.out.println(Arrays.toString(randomBytes));
    }
}

Помимо криптографической защиты SecureRandom имеет гигантский период в 2 160 , по сравнению с периодом Random s 2 48 . У этого есть один недостаток быть значительно медленнее, чем Random и другие линейные PRNG, такие как Mersenne Twister и Xorshift .

Обратите внимание, что реализация SecureRandom зависит от платформы и поставщика. По умолчанию SecureRandom (данный поставщиком SUN в sun.security.provider.SecureRandom ):

  • на Unix-подобных системах, засеянных данными из /dev/random и / или /dev/urandom .
  • в Windows, засеянных вызовами CryptGenRandom() в CryptoAPI .

Выбор случайных чисел без дубликатов

/**
 * returns a array of random numbers with no duplicates
 * @param range the range of possible numbers for ex. if 100 then it can be anywhere from 1-100
 * @param length the length of the array of random numbers
 * @return array of random numbers with no duplicates.
 */
public static int[] getRandomNumbersWithNoDuplicates(int range, int length){
    if (length<range){
        // this is where all the random numbers
        int[] randomNumbers = new int[length];
        
        // loop through all the random numbers to set them
        for (int q = 0; q < randomNumbers.length; q++){
            
            // get the remaining possible numbers
            int remainingNumbers = range-q;
            
            // get a new random number from the remainingNumbers
            int newRandSpot = (int) (Math.random()*remainingNumbers);
            
            newRandSpot++;
            
            // loop through all the possible numbers
            for (int t = 1; t < range+1; t++){
                
                // check to see if this number has already been taken
                boolean taken = false;
                for (int number : randomNumbers){
                    if (t==number){
                        taken = true;
                        break;
                    }
                }
                
                // if it hasnt been taken then remove one from the spots
                if (!taken){
                    newRandSpot--;
                    
                    // if we have gone though all the spots then set the value
                    if (newRandSpot==0){
                        randomNumbers[q] = t;
                    }
                }
            }
        }
        return randomNumbers;
    } else {
        // invalid can't have a length larger then the range of possible numbers
    }
    return null;
}

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


Например, если диапазон равен 5, а длина равна 3, и мы уже выбрали число 2. Тогда у нас есть 4 оставшихся числа, поэтому мы получаем случайное число от 1 до 4 и прокручиваем диапазон (5), пропуская любые числа что мы уже использовали (2).

Теперь предположим, что следующее число, выбранное между 1 и 4, равно 3. В первом цикле мы получаем 1, который еще не был взят, поэтому мы можем удалить 1 из 3, сделав его 2. Теперь во втором цикле мы получим 2, который был взят поэтому мы ничего не делаем. Мы следуем этой схеме до тех пор, пока не дойдем до 4, где, как только мы удалим 1, она станет 0, поэтому мы устанавливаем новый randomNumber равным 4.

Создание случайных чисел с заданным семенем

//Creates a Random instance with a seed of 12345.
Random random = new Random(12345L);

//Gets a ThreadLocalRandom instance
ThreadLocalRandom tlr = ThreadLocalRandom.current();

//Set the instance's seed.
tlr.setSeed(12345L);

Использование одного и того же семени для генерации случайных чисел будет возвращать одинаковые числа каждый раз, поэтому установка другого семени для каждого Random экземпляра является хорошей идеей, если вы не хотите в итоге дублировать числа.

Хорошим методом получения Long который отличается для каждого вызова, является System.currentTimeMillis() :

Random random = new Random(System.currentTimeMillis());
ThreadLocalRandom.current().setSeed(System.currentTimeMillis());

Создание случайного числа с использованием apache-common lang3

Мы можем использовать org.apache.commons.lang3.RandomUtils для генерации случайных чисел с использованием одной строки.

int x = RandomUtils.nextInt(1, 1000);

Метод nextInt(int startInclusive, int endExclusive) принимает диапазон.

Помимо int, мы можем генерировать случайные long , double , float и bytes используя этот класс.

Класс RandomUtils содержит следующие методы:

static byte[] nextBytes(int count) //Creates an array of random bytes.
static double nextDouble() //Returns a random double within 0 - Double.MAX_VALUE
static double nextDouble(double startInclusive, double endInclusive) //Returns a random double within the specified range.
static float nextFloat() //Returns a random float within 0 - Float.MAX_VALUE
static float nextFloat(float startInclusive, float endInclusive) //Returns a random float within the specified range.
static int nextInt() //Returns a random int within 0 - Integer.MAX_VALUE
static int nextInt(int startInclusive, int endExclusive) //Returns a random integer within the specified range.
static long nextLong() //Returns a random long within 0 - Long.MAX_VALUE
static long nextLong(long startInclusive, long endExclusive) //Returns a random long within the specified range.


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow