Вот версия, которую вы можете адаптировать к любому выходному формату, который вам нужен:
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int uniform_5(void)
/* Returns 0, 1, 2, 3 or 4 with uniform probability. Call srand() first.
*/
{
/* Rerolling if we roll below the remainder of RAND_MAX/5 eliminates a
* slight bias caused by RAND_MAX not being evenly divisible by 5, and
* samples x from a uniform distribution.
*/
const int x = rand();
return (x < RAND_MAX % 5) ? uniform_5() : x % 5;
}
bool* fill_bernoulli_80( const ptrdiff_t n, bool output[n] )
/* Fills the output array with n boolean values sampled from a Bernoulli
* distribution with p = 0.8.
*
* Call srand() first.
*/
{
for ( ptrdiff_t i = 0; i < n; ++i ) {
output[i] = uniform_5() < 4;
}
return output;
}
#define NSAMPLES 10000000
int main(void)
{
static bool samples[NSAMPLES];
const unsigned random_seed =
(unsigned)time(NULL)*CLOCKS_PER_SEC + (unsigned)clock();
srand(random_seed);
fill_bernoulli_80( NSAMPLES, samples );
size_t ones = 0;
for ( ptrdiff_t i = 0; i < NSAMPLES; ++i )
ones += samples[i];
printf( "p = %.6f.\n", ones/(double)NSAMPLES );
return EXIT_SUCCESS;
}
Некоторые мои причуды, которые здесь отображаются: я предпочитаю использовать ptrdiff_t
для индексов цикла, потому что математика без знакаможет привести к логическим ошибкам при переполнении или недополнении, которые трудно обнаружить (печально известная 1U < -3
) и int
может иметь ширину 32 бита для 64-разрядной программы.
Вы можете увидеть влияние функционального программирования.на моей хвостовой рекурсивной вспомогательной функции uniform_5
.В данном случае это не является серьезной проблемой, но если вы используете большое число, например RAND_MAX/2 + 2
, вы определенно заметите, что взятие остатка не даст вам равномерного распределения: некоторые числа будут свернуты в два раза чаще, чем другие.Алгоритм перемотки, который я использую, исправляет это.
Я объединяю два источника энтропии в случайное начальное число, время стены и время ЦП, потому что вполне возможно, что программа запускается дважды в одну и ту же секунду.
PRNG по умолчанию часто невелик, но вы также можете легко заменить другой.