Как генерировать случайные 0 и 1, но с 80-20 вероятностью их появления в C? - PullRequest
0 голосов
/ 20 января 2019

Попытка создать программу, которая генерирует два случайных числа (0 и 1) и сохраняет их в массиве и печатает их, что я успешно сделал, проблема в том, что мне нужно, чтобы число 1 генерировалось с вероятностью 80%и число 0 с вероятностью 20%.

Уже выполнено заполнение массива случайными 1 и 0 с rand()%10, поскольку генерируемое случайное число находится в диапазоне от 0 до 10, логика, которую я использовал, заключается в том, что если случайное числобольше 5, сохранить его в массиве как '1', а если меньше 5, сохранить в массиве как '0'

for(i=0;i<=n_gen;i++)               // for allele array
{
     randallele[i]=rand()%10 +1;
     if(randallele[i]>=5)
     {
         randallele[i]=1;
     }
     else
     {
         randallele[i]=0;
     }

}
for(i=0;i<=n_gen;i++)           //prints allele array
{
    printf("Printing the alleles:    %d\n", randallele[i]);
}

Я ожидаю, что выходные данные будут сгенерированы вместе с их вероятностями (80% для '1' и 20% для '0') вместо непосредственного хранения случайных 1 и 0 *

Спасибо

Ответы [ 2 ]

0 голосов
/ 20 января 2019

Вот версия, которую вы можете адаптировать к любому выходному формату, который вам нужен:

#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 по умолчанию часто невелик, но вы также можете легко заменить другой.

0 голосов
/ 20 января 2019

потому что

randallele[i]=rand()%10 +1;

получить число от 1 до 10, набрав

if(randallele[i]>=5)
{
    randallele[i]=1;
}
else
{
    randallele[i]=0;
}

у вас есть 5..10 = 6 возможностей, чтобы получить 1, и 0..4 = 5, чтобы получить 0

Чтобы иметь 80% 1 и 20% 0, вам просто нужно изменить:

 if(randallele[i]>=3)
 {
     randallele[i]=1;
 }
 else
 {
     randallele[i]=0;
 }

потому что 3..10 = 8 возможностей и 1..2 только 2

Более короткий способ получить тот же результат - просто иметь:

randallele[i]=rand()%10 +1;
randallele[i] = (randallele[i]>=3);

наконец-то

randallele[i] = ((rand()%10) >= 2);

Маленькая программа для тестирования:

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

int main()
{
  int n[2] = {0};

  for (int i = 0; i != 100000; i++)
    n[((rand()%10) >= 2)] += 1;

  printf("%d %d => %g%% %g%%\n",
         n[0], n[1], round(n[0] / 1000.0), round(n[1] / 1000.0));

  return 0;
}

Исполнение:

20202 79798 => 20% 80%

Примечание: чтобы не иметь все время одного и того же результата, простой способ - сделать srand(time(0)); перед использованием rand()

...