Я не знаю математику, но я знаю, что FindBugs жалуется, если вы используетеMath.random()
finnw
3
Помните, что у Random нет статического метода, поэтому используйте: (new Random ()). NextInt (n)). Чтобы Math генерировал похожее целое число, используйте: Math.floor ((Math.random () * n) +1);
Дмитрий Деваэле
Ответы:
169
Вот подробное объяснение того, почему « Random.nextInt(n)и более эффективно, и менее предвзято, чем Math.random() * n» из постов на форумах Sun, на которые ссылается Гили:
Math.random () использует Random.nextDouble () для внутреннего использования.
Random.nextDouble () использует Random.next () дважды, чтобы сгенерировать двойник, который имеет приблизительно равномерно распределенные биты в своей мантиссе, поэтому он равномерно распределен в диапазоне от 0 до 1- (2 ^ -53).
Random.nextInt (n) использует Random.next () в среднем менее чем в два раза - он использует его один раз, и если полученное значение выше максимального кратного n ниже MAX_INT, он пытается снова, в противном случае возвращает значение по модулю n (это предотвращает перекос распределения значений выше максимального кратного n ниже MAX_INT), возвращая значение, которое равномерно распределено в диапазоне от 0 до n-1.
До масштабирования на 6 вывод Math.random () является одним из 2 ^ 53 возможных значений, полученных из равномерного распределения.
Масштабирование на 6 не изменяет количество возможных значений, и приведение к int затем приводит к принудительному переводу этих значений в одно из шести «сегментов» (0, 1, 2, 3, 4, 5), каждое из которых соответствует диапазонам, охватывающим либо 1501199875790165 или 1501199875790166 из возможных значений (так как 6 не является диссидентом 2 ^ 53). Это означает, что при достаточном количестве бросков кубиков (или фильере с достаточно большим числом сторон) матрица будет демонстрировать смещение в сторону больших ковшей.
Вы будете очень долго ждать, пока этот эффект проявится.
Math.random () также требует примерно двойной обработки и подлежит синхронизации.
Random.nextInt и nextDouble также подлежат синхронизации.
Адрианос
В этом контексте, что означает «менее предвзятый», пожалуйста?
ΦXocę 웃 Пепеупа ツ
2
@ ΦXocę 웃 Пепеупа ツ Это просто означает, что некоторые числа будут нарисованы с большей вероятностью, чем другие. Как и в случае с предвзятым отношением некоторых чисел к другим (следовательно, не полностью случайным или не имеющим достаточно большой размер выборки)
брод префект
1
Обратите внимание, что последний комментарий к этой теме сообщает: «Описанное смещение составляет одну часть в 2 ^ 53, но максимальная длина цикла используемого PRNG составляет всего 2 ^ 48. Поэтому в приложении вы увидите данные Распределение базового PRNG, а не смещение ". Это указывает на то, что оба метода эквивалентны
цифровая иллюзия
1
@ ΦXocę 웃 ПepeúpaツЗаменить 6с 5на кости кубе: это будет «5-предвзятым». Вы можете бросить кубик пару раз, прежде чем заметите, что с кубиком что-то не так. Вы вынуждены провести чрезвычайно сложное тщательное исследование, прежде чем заметите, что что-то не так с генератором случайных чисел.
Давид Хорват
27
Еще одним важным моментом является то, что Random.nextInt (n) повторяется, так как вы можете создать два объекта Random с одинаковым начальным числом . Это невозможно с помощью Math.random ().
Я бы порекомендовал на самом деле процитировать некоторые из его постов и кратко изложить здесь. Ссылка должна быть дополнительной к вашему ответу.
jjnguy
0
Согласно этому примеру Random.nextInt(n)вывод будет менее предсказуемым, чем Math.random () * n. В соответствии с [отсортированный массив быстрее, чем несортированный массив] [1] я думаю, что мы можем сказать, что Random.nextInt (n) трудно предсказать .
usingRandomClass: время: 328 мсек.
usingMathsRandom: время: 187 мсек.
package javaFuction;import java.util.Random;publicclassRandomFuction{staticint array[]=newint[9999];staticlong sum =0;publicstaticvoid usingMathsRandom(){for(int i =0; i <9999; i++){
array[i]=(int)(Math.random()*256);}for(int i =0; i <9999; i++){for(int j =0; j <9999; j++){if(array[j]>=128){
sum += array[j];}}}}publicstaticvoid usingRandomClass(){Random random =newRandom();for(int i =0; i <9999; i++){
array[i]= random.nextInt(256);}for(int i =0; i <9999; i++){for(int j =0; j <9999; j++){if(array[j]>=128){
sum += array[j];}}}}publicstaticvoid main(String[] args){long start =System.currentTimeMillis();
usingRandomClass();long end =System.currentTimeMillis();System.out.println("usingRandomClass "+(end - start));
start =System.currentTimeMillis();
usingMathsRandom();
end =System.currentTimeMillis();System.out.println("usingMathsRandom "+(end - start));}}
Во втором цикле вы проверяете на> = 50, что верно в более чем 50% случаев. Это приведет к тому, что выражение if будет верным в большинстве случаев, что сделает его более предсказуемым. Поэтому ваши результаты смещены в пользу вашего ответа
Нейрон
это опечатка ... сделайте 128 во втором примере, вы получите тот же результат.
Math.random()
Ответы:
Вот подробное объяснение того, почему «
Random.nextInt(n)
и более эффективно, и менее предвзято, чемMath.random() * n
» из постов на форумах Sun, на которые ссылается Гили:источник
6
с5
на кости кубе: это будет «5-предвзятым». Вы можете бросить кубик пару раз, прежде чем заметите, что с кубиком что-то не так. Вы вынуждены провести чрезвычайно сложное тщательное исследование, прежде чем заметите, что что-то не так с генератором случайных чисел.Еще одним важным моментом является то, что Random.nextInt (n) повторяется, так как вы можете создать два объекта Random с одинаковым начальным числом . Это невозможно с помощью Math.random ().
источник
Согласно https://forums.oracle.com/forums/thread.jspa?messageID=6594485龵
Random.nextInt(n)
и более эффективный, и менее предвзятый, чемMath.random() * n
источник
Согласно этому примеру
Random.nextInt(n)
вывод будет менее предсказуемым, чем Math.random () * n. В соответствии с [отсортированный массив быстрее, чем несортированный массив] [1] я думаю, что мы можем сказать, что Random.nextInt (n) трудно предсказать .usingRandomClass: время: 328 мсек.
usingMathsRandom: время: 187 мсек.
источник