Неправильно подсчитывается период генератора случайных чисел в основе которого лежит линейный конгруэтный метод, что делать?

Неправильно подсчитывается период генератора случайных чисел в основе которого лежит линейный конгруэтный метод, что делать?

   public class Main {
    
        public static void main(String[] args) {
            double x = 1;
            int count = 0;
            int per = 0;
            double num = 0;
            int m = (int) Math.pow(2, 32);
            double M = Math.pow(2, 32);
            int b = 134775813;
            int k = 1;
            ArrayList<Double> array = new ArrayList<>();
            for (int j = 0; j < m; j++) {
    
                x = (k * x + b) % M;
                num = x / M;
    
                array.add(num);
                //Нахождение периода генератора
                count = Collections.frequency(array, num);
                if (count >= 2) {
                    per = j;
                    break;
                }
            }
            System.out.println(per);
        }
    }

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

Автор решения: Aziz Umarov

Считает неправильно потому что неправильно реализован сам метод.

Вы делаете

x = (k * x + b) % M;
  1. М заведомо очень большое что будет вам гарантировать большой остаток.
  2. М почему вещественное
  3. Зачем x делить на М. М большое х меньше результат num вещественное меньше 1.
  4. Collections.frequency вернет количество num в списке а не период.

Исправьте по замечаниям и можно будет подумать.

Updated.

Чуток поменял ваш код.

public static void main(String[] args) {
    double x = 1;
    int count = 0;
    int per = 0;
    double num = 0.0;
    long m = Math.round(Math.pow(2, 32));
    double M = 100000.0; // Math.pow(2, 32);

    long b = 134775813L;
    long k = 1L;

    List<Double> array = new ArrayList<>();
    for (int j = 0; j < m; j++) {

      x = (k * x + b) % M;
      num = x / M;

      if (array.contains(num)) {
        count = array.indexOf(num);
        per = j - count;
        break;
      }
      array.add(num);
    }
    System.out.println(String.format("period = %d", per));
    // System.out.println(array);
  }
}

Ваши ошибки.

  1. int m = (int) Math.pow(2, 32); m = 0 в результате
  2. double M = Math.pow(2, 32); если брать такое же число то вы получите период М
  3. count = Collections.frequency(array, num); - возращяет количество num в массиве

и для примера из вики

public static void main(String[] args) {
    double x = 7;
    int count = 0;
    int per = 0;
    double num = 0.0;
    long m = Math.round(Math.pow(2, 32));
    double M = 10.0; // Math.pow(2, 32);

    long b = 7L;
    long k = 7L;

    List<Double> array = new ArrayList<>();
    for (int j = 0; j < m; j++) {

      x = (k * x + b) % M;
      num = x / M;

      if (array.contains(num)) {
        count = array.indexOf(num);
        per = j - count;
        break;
      }
      array.add(num);
    }
    System.out.println(String.format("period = %d", per));
    // System.out.println(array);
  }
}

периоды совпадают

Update 2. для примера в коментариях. Использовал более быструю структуру в данном случае.

public static void main(String[] args) {
    double x = 7;
    int count = 0;
    int per = 0;
    double num = 0.0;
    long m = Math.round(Math.pow(2, 32));
    double M = 1771875.0; // Math.pow(2, 32);

    long b = 374441L;
    long k = 2416L;

    Map<Double, Double> array = new HashMap<>();
    for (int j = 0; j < m; j++) {

      x = (k * x + b) % M;
      num = x / M;

      if (array.containsKey(num)) {
        // count = array.indexOf(num);
        // per = j - count;
        per = array.size();
        break;
      }
      array.put(num, num);
    }
    System.out.println(String.format("period = %d", per));
    // System.out.println(array);
  }
→ Ссылка