Генератор псевдослучайных чисел на python

#python #random

Вопрос:

Я попытался выполнить следующий код с помощью python:

введите описание изображения здесь

Мой код таков:

 #UNIFORM RANDOM SAMPLING 

import numpy as np                #library needed for numerical calculations
import matplotlib.pyplot as plt   #library needed for plotting purposes
from time import process_time     #function needed for checking CPU time
from scipy.stats import chisquare #function needed for chi square test

#*******************************************************************************

i=np.uintc(987654321)              #unsigned int variable i with seed 987654321

r=2**30                            #range of the sequence

t1_start=process_time()            #process start time 

for count in range(r):             #for cycle over expected period and update i

    i=np.uintc(i*663608941)

t1_stop=process_time()             #process stop time
    
print("nLoop stopped at the element:", i, ".n")     
print("Is this the last element of the series? 1 for YES other numbers for NO", i/987654321,".n")
print("The CPU time needed in order to take to go throught the whole sequence is", t1_stop-t1_start, "seconds.n")
 

Тем временем выход:

введите описание изображения здесь

Как вы можете видеть, программа просыпается, но не очень оптимизирована ( почти 1 час работы).

Как я могу оптимизировать его и получить желаемый результат за много секунд?

Комментарии:

1. Я не думаю, что здесь слишком много места для оптимизации. Как насчет 987654321*pow(663608941, 2**30, 0xFFFFFFFF) этого ?

2. Работает, спасибо! Но я не понимаю, что это такое 0xFFFFFFF?

3. @J. Сноуден, это неверно. Должно быть 1<<32 для возведения в степень mod 2^32 (размер без знака int). Результат тот же (потому pow(663608941, 2**30, 1<<32)==1 что ), но, как я уже упоминал ниже, это не проверяет наличие более коротких циклов в последовательности.

4. По сути 987654321* 663608941^(2**30) % 0xFFFFFFFF) , так оно и есть . 0xFFFFFFFF является максимальным значением 32-разрядного целого числа. mod 0xFFFFFFFF предназначен для имитации арифметических операций над 32-разрядным целым числом. pow Функция использует модульный алгоритм возведения в степень внутри, что более эффективно, чем простой итерационный алгоритм. Но, как сказал @r3mainer, он не проверяет длину более короткой последовательности. Таким образом, это может не соответствовать описанию проблемы.

5. @Dummmy Нет, 32-разрядная арифметика выполняется по модулю 2^32 (0x100000000), а не 2^32-1 (0xffffffff). Ты отстаешь на час.

Ответ №1:

Вам обязательно использовать Python?

Код будет работать намного быстрее в C. При компиляции с -O3 оптимизацией для запуска на моем рабочем столе требуется около секунды:

 #include <stdio.h>
#include <inttypes.h>

int main() {
    uint32_t i, n;
    i = 987654321;
    n = 0;
    while (1) {
        n  ;
        i *= 663608941;
        if (i == 987654321) break;
    }
    printf("Sequence repeats after %" PRIu32 " iterations.n", n);
    printf("Expected value: %d.n", 1<<30);
    return 0;
}
 

Я также должен отметить, что ваш код не совсем корректен. Это подтверждает, что последовательность возвращается в исходное состояние после 2 30 итераций, но не проверяет наличие других вхождений i=987654321 во время цикла.


Если вы застряли с использованием Python, похоже, что целочисленные типы numpy не дают большого преимущества с точки зрения скорости. Следующий код выполняется на моем компьютере примерно за 200 секунд.:

 def seq_check():
    x = 987654321
    n = 0
    while True:
        n  = 1
        x = (x * 663608941) amp; 0xffffffff
        if x == 987654321:
            break
    return n
 

Комментарии:

1. Я согласен с вашим комментарием, вы правы. Да, я не хотел использовать Python, спасибо.

2. Я не знаю, почему, но в моей машине код не работает, возвращает x=x и n=1000000.

3. В этом нет никакого смысла. Как он может возвращать два значения? Если вы просто выведете возвращаемое значение из этой функции (т. е., print(seq_check()) ), оно должно означать 1073741824.

4. Прости, это была моя вина. Код запускается за 6 минут с помощью Google colab.

5. Я также пытаюсь проверить процессорное время, ставя перед def seq_check() и после него строку t1_start=process_time() и t1_stop=process_time() соответственно. Но это возвращает время процессора fals, около 1e-5.