Мне нужен PRNG для проекта моделирования, и нашел ресурс что, учитывая мое ограниченное, но не несуществующее знание PRNG, кажется обоснованным и хорошо информированным. Я пытаюсь инкапсулировать алгоритмы, приведенные в этом отчете, в класс, но по некоторым причинам я получаю много повторяющихся значений. Может быть, просто то, что PRNG не так хорош, как говорится в отчете, но я подозреваю, что в моей реализации что-то не так.
Следующий пример кода приведен на странице 3:
/* Public domain code for JKISS RNG */
// seed variables
static unsigned int x = 123456789,y = 987654321,z = 43219876,c = 6543217;
unsigned int JKISS()
{
unsigned long long t;
x = 314527869 * x + 1234567;
y ^= y << 5; y ^= y >> 7; y ^= y << 22;
t = 4294584393ULL * z + c; c = t >> 32; z = t;
return x + y + z;
}
В связи с этим в докладе утверждается, что
Период JKISS составляет ≈2 127 = 1,7×10 38 (2 32 x (2 32 -1) x (1/2 *)
4294584393 x 2 32 — 1)) и он проходит все тесты Dieharder и полный набор тестов BigCrunch в
Testu01.
так что это определенно кажется мне достаточно хорошим. Далее в отчете (стр. 6) говорится
Следующий код C генерирует [sic] случайное число (с двойной точностью) с плавающей запятой 0 <= х < 1:
double x; x = JKISS() / 4294967296.0;
У меня есть следующее в заголовочном файле:
class JKISS : public IPRNG {
private:
// Seed variables
static unsigned int x;
static unsigned int y;
static unsigned int z;
static unsigned int c;public:
static unsigned int randui32();
static double randdouble();
};
со следующим файлом реализации
#include "prng.hpp"
unsigned int JKISS::x = 123456789;
unsigned int JKISS::y = 987654321;
unsigned int JKISS::z = 43219876;
unsigned int JKISS::c = 6543217;
unsigned int JKISS::randui32() {
unsigned long long t;
x = 314527869 * x + 1234567;
y ^= y << 5; y ^= y >> 7; y ^= y << 22;
t = 4294584393ULL * z + c; c = t >> 32; z = t;
return x + y + z;
}
double JKISS::randdouble() {
return randui32() / 4294967296.0;
}
и следующая основная программа
#include <iostream>
#include "prng.hpp"
int main() {
for (int i = 0; i < 10000; ++i) {
std::cout << JKISS::randdouble() << std::endl;
}
}
Как видите, я скопировал большую часть кода.
Однако, когда я запускаю это, я получаю 68 повторяющихся значений, хотя я просто извлекаю 10 000 значений. Это говорит мне о том, что что-то не так с моей инкапсуляцией, но я не могу понять, в чем проблема.
В случае, если это имеет значение, я использую GCC 4.8.1 в Ubuntu 13.10 со следующими характеристиками:
Platform Info:
System: Linux (x86_64-linux-gnu)
CPU: Intel(R) Xeon(R) CPU E5410 @ 2.33GHz
WORD_SIZE: 64
Любые идеи относительно того, что может вызвать это, приветствуются.
Я получаю те же результаты, что и вы, но без дубликатов; p
Я имею в виду, что если я запускаю вашу программу в соответствии с указаниями, я получу 68 дубликатов, но если я переключусь randdouble()
=> randui32()
дубликатов больше нет, поэтому держу пари, что они были артефактом из-за точности процедуры печати.
Вы можете попытаться собрать двойные значения в массиве и сравнить их, чтобы убедиться на 100%.
Вы возвращаете float
в то время как оригинальный код генерирует double
,
Зачем? Что заставляет вас думать, что какая-то случайная страница в Интернете даст вам лучшую ГСЧ, чем те, которые встроены в вашу стандартную библиотеку C ++, которая предоставляет все виды отличных функций, упакованных и готовых к использованию? Ты действительно в состоянии оценить, если то, что вы нашли, лучше для ваших целей?
Похоже, что напечатанный вывод составляет всего шесть значащих цифр, что означает, что у вас есть что-то вроде 1000000 уникальных значений отображения (это упрощено — есть больше возможностей, но распределение искажено). Фактически вы печатаете 10000 значений из пула 1000000. I считать 68 дубликатов разумно в этой ситуации.