Math.random () проти Random.nextInt (int)


135

Яка різниця між Math.random() * nі Random.nextInt(n)де nціле число?


Я не знаю математики, але я знаю, що FindBugs скаржиться, якщо ви використовуєтеMath.random()
finnw

3
Пам'ятайте, що у Random немає статичного методу, тому використовуйте: (новий 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, воно намагається знову, інакше повертає значення modulo 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 () також вимагає приблизно двічі обробки та підлягає синхронізації.


3
Random.nextInt і nextDouble також підлягають синхронізації.
adrianos

У цьому контексті, що означає "менш упереджене", будь ласка?
ΦXocę 웃 Pepeúpa ツ

2
@ ΦXocę 웃 Пепеупа ツ Це просто означає, що певні числа мають більше шансів отримати інші, ніж інші. Оскільки в ньому упереджено вибирати одні цифри над іншими (отже, не зовсім випадковими або даними достатньо великими розмірами вибірки)
префект форд

1
Зауважте, що останній коментар до цього потоку повідомляє: "Описаний ухил є однією частиною в 2 ^ 53, але максимальна тривалість циклу використовуваного PRNG становить лише 2 ^ 48. Отже, що ви побачите в додатку, це дані розподіл основної PRNG, а не упередженість ". Це вказувало б на те, що два способи рівнозначні
цифрова ілюзія

1
@ ΦXocę 웃 ПepeúpaツЗамінити 6з 5на кістки кубі: це буде «5-упередженим». Ви можете кинути кістки кілька разів, перш ніж помітите, що з кісткою щось не так. Ви змушені провести надзвичайно складне ретельне обстеження, перш ніж помітите, що з випадковим генератором щось не так.
Давид Хорват

27

Ще один важливий момент полягає в тому, що Random.nextInt (n) є повторюваним, оскільки ви можете створити два випадкових об'єкта з одним і тим же насінням. Це неможливо з Math.random ().



0

Відповідно до цього прикладу Random.nextInt(n)має менш передбачуваний вихід, ніж Math.random () * n. Відповідно до [відсортований масив швидше, ніж несортований масив] [1] Я думаю, що ми можемо сказати, що Random.nextInt (n) важко передбачити .

usingRandomClass: час: 328 миль секунди.

usingMathsRandom: час: 187 миль секунди.

package javaFuction;
import java.util.Random;
public class RandomFuction 
{
    static int array[] = new int[9999];
    static long sum = 0;
    public static void 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];
                }
            }
        }
    }

    public static void usingRandomClass() {
        Random random = new Random();
        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];
                }
            }

        }

    }

    public static void 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));

    }

}

1
У другому циклі ви перевіряєте наявність> = 50, що відповідає більш ніж 50% випадків. Це спричинить це, якщо твердження буде правдивим більшість разів, що робить його більш передбачуваним. Тому ваші результати упереджені на користь вашої відповіді
Нейрон

це помилка помилки ... зробіть 128 у другому прикладі, ви отримаєте такий же результат.
Джатин Гоял
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.