2014-10-13 6 views
2

Я новичок в программировании на С, и я прочитал, что erand48() - хороший вариант для генерации случайных чисел, защищенных потоками. Однако функция принимает начальное значение: unsigned short int array [3]Какое начальное значение следует использовать для erand48() в C?

Любые рекомендации относительно того, для чего должно быть инициализировано это начальное значение?

+0

Почему не то же самое, что' srand': 'time'? Поскольку у вас есть еще несколько бит для заполнения, возможно, запустите' pid' – usr2564301

+1

@Jongware, потому что 'time' не обновляется нигде близко к тому, чтобы там была разница между потоками (1s для' libc: time', <1ms для 'pthread: create'). – haneefmubarak

+0

@haneef: thanks Я полностью забыл про потоки, и, действительно, это возможно (если не просто * обычно *) будет создано несколько потоков в том же миллисекунде. – usr2564301

ответ

1

Хорошо. Поэтому прежде всего позвольте мне пояснить, что PRNG в libc является детерминированным (вот почему он хочет семя), использует LCG - это означает, что легко предсказать все значения, если у вас есть несколько, и, следовательно, небезопасно.

Теперь то. erand48() возвращает случайное значение с плавающей запятой double размер от равномерного распределения псевдослучайных действительных чисел. Он не принимает начальное значение как таковое, а скорее требует предоставить буфер состояния. Вот полное описание:

double erand48(unsigned short xsubi[3]); 

состояние буфера, достаточно занятно, должны быть посеяны на случайное значение для того, чтобы генератор работать. Моя первая мысль заключалась в том, чтобы читать от /dev/urandom.

Мы можем сделать это с чем-то вроде этого (с помощью небуферизован читает, чтобы предотвратить потери от таких маленьких читает):

#include <stdio.h> 
#include <stdlib.h> 

void *thread_f (void *i) { 
    // setup unbuffered urandom 
    urandom = fopen ("/dev/urandom", "r"); 
    setvbuf (urandom, NULL, _IONBF, 0); // turn off buffering 

    // setup state buffer 
    unsigned short randstate[3]; 
    // fgetc() returns a `char`, we need to fill a `short` 
    randstate[0] = (fgetc (urandom) << 8) | fgetc (urandom); 
    randstate[1] = (fgetc (urandom) << 8) | fgetc (urandom); 
    randstate[2] = (fgetc (urandom) << 8) | fgetc (urandom); 


    // cleanup urandom 
    fclose (urandom); 

    // you can now use erand48 (randstate); 

    ...  // do whatever work you need to do 

    return result; 
} 

Это поточно, и даже обеспечивает относительно безопасное начальное значение для всех нитей ,

Конечно, если скорость не слишком большая проблема (то есть: вы можете жить с небольшой потерей скорости), и вы можете жить с целыми числами, а делать небуферизованные чтения напрямую с /dev/urandom - идеальное решение. Еще лучше,/dev/urandom обеспечивает безопасные, непредсказуемые псевдослучайные целые числа (ну, технически, поток байтов, но они всегда будут работать как целые, если вы соответствуете размеру), которые также обычно распределяются равномерно.

Плюс, /dev/urandom Периодически в него вводится энтропия и обновляется, гарантируя, что у вас есть приличная поставка довольно случайных чисел.

+0

Функции IO ARE потокобезопасны (вот почему у вас есть getc_unlocked и друзья); (nitpick -on) fgetc возвращает один байт, вам нужно два, а ссылка LCG указывает на LFSR (nitpick-off) – loreb

+0

@loreb Я не знаю, почему я думал, что это не так. В любом случае, исправлены LCG и 'fgetc() 'Спасибо за указание вне! – haneefmubarak

1

Просто мои 2 цента ...

Мы использовали ту же функцию семью в одном из наших проектов, когда-то давно. Продукт должен был работать на Windows/Unix, поэтому мы не использовали /dev/random.

Вместо этого мы объединили host_ip_addr + time() + process_id + thread_id как строку и сгенерировали хэш из этой строки. И затем мы распространили XOR'ed на завершающие байты на 6 ведущих байтов. Мы использовали, что окончательные данные как нашего семени ...

0

Семейство rand48 является 48 бит LCG, что означает что-то вроде

double erand48(uint48_t *state) { 
    *state = *state * A + C;    /* A and C are suitable values */ 
    return *state/281474976710656.0; /* that's 2^48 */ 
} 

... за исключением того, что я никогда не видел компьютер с uint48_t, поэтому то, что вы проходите, это массив с 48 бит состояния (3x16, предполагая, что короткий имеет 16 бит). Вы можете засеять его чем угодно - просто получите 48 случайных бит и засуньте их в массив [3], из/dev/urandom, from time/pid/whatever.

Несколько заготовок: - lcong48() - забыть даже о существовании - «Как я могу убедиться, что два семени не смехотворно близки друг к другу?«Нет, это займет меньше времени, чтобы просто использовать другой rng.

Смежные вопросы