Java Math.random повторяет значения. Доска Гальтона

Это программа демонстрирует работу доски Гальтона. Эта доска имеет N шт. слот снизу и одна дыра сверху. Сверху подают шарики которые случайным образом попадают в один из N слотов. Доску используют чтобы исследовать теорию вероятностей.

Смотрите здесь https://ru.wikipedia.org/wiki/Доска_Гальтона

Во время тестирования выявилось, что методы Math.random(), Random.nextInt(), Random.nextBoolean() и т.д. возвращают одинаковые результаты.


import java.util.Arrays;
import java.util.Random;
import java.util.Scanner;


public class Main {

    public static Scanner scan = new Scanner(System.in);

    // Генератор случайных чисел
    public static Random rand = new Random();

    public static void main(String[] args) {
        // слоты
        int[] slots;

        // количество слотов
        int n;

        // количество шариков
        int balls;

        // показывает на какую сторону катиться шарик false - налево, true - направо
        boolean side;

        // индекс слота в которую должен попасть текущий шарик
        int k;

        // середина массива
        int middle;

        // количество повторения эксперимента
        int times;

        // показывает наибольшое количество шариков в одном слоте
        int max;

        // initialization
        System.out.print("Enter number of repetitions: ");
        times = scan.nextInt();

        System.out.print("Enter number of balls: ");
        balls = scan.nextInt();

        System.out.print("Enter number of slots: ");
        n = scan.nextInt();
        slots = new int[n];
        middle = n / 2;

        while (times > 0) {
            while (balls > 0) {
                k = 0;
                for (int i = 0; i < n - 1; i++) {
                    // "случайный" true или false, от которого зависит значения k
                    side = rand.nextBoolean();
                    k = (side) ? k + 1 : k - 1;
                }

                // так как 2 катание шарика соответствуют одному изменению индекса
                // делим на 2, слагаем алгебраически
                k = middle + k / 2;

                // добавляем шарик в слоте, уменьшаем количество оставшейся шариков
                slots[k]++;
                balls--;
            }

            // находим максимум, рисуем
            max = Max(slots);
            while(max > 0) {
                for(int slot : slots) {
                    if (slot >= max) {
                        System.out.print(" O ");
                    } else {
                        System.out.print("   ");
                    }
                }
                System.out.println();
                max--;
            }

            System.out.println(Arrays.toString(slots) + "\n");
            times--;
        }
    }

    public static int Max(int[] array) {
        int max = 0;
        for (int i = 1; i < array.length; i++) {
            if(array[max] < array[i]) {
                max = i;
            }
        }
        return array[max];
    }
}

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

testing

Здесь я повторяю эксперимент 2 раз, но 2-ой эксперимент ничем не отличается от 1-ой.
Почему же это так, с чем это связано и как всегда получить уникальные значения?

P.S. Пробовал

    public static Random rand = new Random(System.currentTimeMillis());

и еще в цикле попыток

    while (times > 0) {
        //code...
        rand = new Random(System.currentTimeMillis());
   }
   // code...

или же

    while (times > 0) {
        //code...
        rand.setSeed(System.currentTimeMillis());
   }
   // code...

не помогло


Ответы (1 шт):

Автор решения: becouse

Нужно инициализировать генератор случайных чисел.

 Random rand = new Random(System.currentTimeMillis());

По умолчанию инициализпция идёт одним и тем же числом.

Но основная проблема другая и вы легко увидели бы ее, если бы запустили программу пошагово.

Смотрите:

// добавляем шарик в слоте, уменьшаем количество оставшейся шариков
                slots[k]++;
                balls--;

Чему будет равно balls после первого прохода по циклу? Понятно, что нулю и при втором проходе вам просто распечатается содержимое slots.

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

Вот исправленный код.

import java.util.Arrays;
import java.util.Random;
import java.util.Scanner;


public class Main {

    public static Scanner scan = new Scanner(System.in);

    // Генератор случайных чисел
    public static Random rand = new Random(System.currentTimeMillis());

    public static void main(String[] args) {
        // слоты
        int[] slots;

        // количество слотов
        int n;

        // количество шариков
        int balls;

        // показывает на какую сторону катиться шарик false - налево, true - направо
        boolean side;

        // индекс слота в которую должен попасть текущий шарик
        int k;

        // середина массива
        int middle;

        // количество повторения эксперимента
        int times;

        // показывает наибольшое количество шариков в одном слоте
        int max;

        // initialization
        System.out.print("Enter number of repetitions: ");
        times = scan.nextInt();

        System.out.print("Enter number of balls: ");
        balls = scan.nextInt();
        int balls_current;

        System.out.print("Enter number of slots: ");
        n = scan.nextInt();

        middle = n / 2;


        while (times > 0) {
            balls_current=balls;
            slots = new int[n];
            while (balls_current > 0) {
                k = 0;
                for (int i = 0; i < n - 1; i++) {
                    // "случайный" true или false, от которого зависит значения k
                    side = rand.nextBoolean();
                    k = (side) ? k + 1 : k - 1;
                }

                // так как 2 катание шарика соответствуют одному изменению индекса
                // делим на 2, слагаем алгебраически
                k = middle + k / 2;

                // добавляем шарик в слоте, уменьшаем количество оставшейся шариков
                slots[k]++;
                balls_current--;
            }

            // находим максимум, рисуем
            max = Max(slots);
            while(max > 0) {
                for(int slot : slots) {
                    if (slot >= max) {
                        System.out.print(" O ");
                    } else {
                        System.out.print("   ");
                    }
                }
                System.out.println();
                max--;
            }

            System.out.println(Arrays.toString(slots) + "\n");
            times--;
        }
    }

    public static int Max(int[] array) {
        int max = 0;
        for (int i = 1; i < array.length; i++) {
            if(array[max] < array[i]) {
                max = i;
            }
        }
        return array[max];
    }
}
→ Ссылка