Получить true или false с заданной вероятностью

Я пытаюсь написать функцию на c++, которая вернет true или false на основе заданной вероятности. Так, например, если заданная вероятность равна 0,634, то 63,4% времени функция будет возвращать true. Я пробовал разные вещи и потерпел неудачу. Любой помочь?

2 ответов


если вы хотите сделать это в C++11, вы можете использовать его различные движки случайных чисел в сочетании с uniform_real_distribution обеспечить хороший результат. Следующий код демонстрирует:

#include <random>

std::knuth_b rand_engine;  // replace knuth_b with one of the engines listed below
std::uniform_real_distribution<> uniform_zero_to_one(0.0, 1.0);

bool random_bool_with_prob( double prob )  // probability between 0.0 and 1.0
{
    return uniform_zero_to_one(rand_engine) >= prob;
}

можно использовать bernoulli_distribution, который непосредственно дает вам bool с заданной вероятностью. Вероятность того, что это займет, - это вероятность возвращения true, поэтому это именно то, что вам нужно:

#include <random>

std::knuth_b rand_engine;  // replace knuth_b with one of the engines listed below

bool random_bool_with_prob( double prob )  // probability between 0.0 and 1.0
{
    std::bernoulli_distribution d(prob);
    return d(rand_engine);
}

если ваша вероятность фиксирована, то вы можете переместить ее из функция выглядит так:

#include <random>

std::knuth_b rand_engine;  // replace knuth_b with one of the engines listed below
std::bernoulli_distribution random_bool_generator( prob );  // replace "prob" with your probability

bool random_bool()
{
    return random_bool_generator( rand_engine );
}

или если вы хотите получить еще более причудливым, вы можете связать их вместе:

#include <random>
#include <functional>

std::knuth_b rand_engine;  // replace knuth_b with one of the engines listed below
std::bernoulli_distribution random_bool_generator( prob );  // replace "prob" with your probability

auto random_bool = std::bind( random_bool_generator, rand_engine )

// Now call random_bool() to get your random boolean with the specified probability.

вы можете заменить knuth_b С любым из стандартных двигателей:

  • std::linear_congruential_engine
  • std::mersenne_twister_engine
  • std::subtract_with_carry_engine

или многие другие, которые являются версиями выше, параметризованы различными способами. Моя ссылка перечисляет следующее:

  • std::default_random_engine (реализация определенный.)
  • std::minstd_rand0
  • std::minstd_rand
  • std::mt19937
  • std::mt19337_64
  • std::ranlux24_base
  • std::ranlux48_base
  • std::ranlux24
  • std::ranlux48
  • std::knuth_b

и если этого недостаточно, есть некоторые стандартные адаптеры, которые могут еще больше нарушить последовательность случайных чисел:

  • std::discard_block_engine который адаптирует двигатель, отбрасывая заданное число генерируемые значения каждый раз.
  • std::independent_bits_engine, который адаптирует двигатель для получения случайных величин с заданным количеством битов. (Не важно для вашей конкретной потребности.)
  • std::shuffle_order_engine который адаптирует двигатель путем перестановки порядка их генерируемых значений.

генераторы во втором списке являются производными от базовых генераторов в первом списке, либо с конкретными параметрами, адаптерами или обоими. Например, knuth_b эквивалентно shuffle_order_engine< linear_congruential_engine< uint32_t, 16807, 0, 2147483647>, 256>, согласно моему справочнику. (Стандартная Библиотека C++, Второе Издание, Николаем Джосутису, многие контрольной работы.)

вы можете найти более подробную информацию в интернете, в том числе это краткое введение здесь:http://en.wikipedia.org/wiki/C++11#Extensible_random_number_facility

здесь больше документации:http://en.cppreference.com/w/cpp/numeric/random

вы, вероятно, хотите чтобы изменить объявление rand_engine выше, чтобы обеспечить семя. В приведенном выше примере используется семя по умолчанию. Смотри cppreference.com как посеять его, если вы хотите другое семя.


#include <stdlib.h>
bool prob_true(double p){
    return rand()/(RAND_MAX+1.0) < p;
}

логика:

rand() возвращает случайное число между 0 и RAND_MAX (включая оба), с равной вероятностью для каждого номера. Итак, разделив результат на RAND_MAX мы получаем случайное число между 0 и 1. Это позволяет нам выбрать район - в вашем примере 63.4% этого сегмента, например,0 to 0.634 - и проверьте, упал ли результат в этой области.

теперь приходит сложная часть: мы не хотим, чтобы получить оба 0 и 1! Почему? Потому что мы хотим вероятности 0 чтобы никогда не быть правдой, поэтому нам нужны <p (вместо <=p) - так что когда p=0 вы никогда не получите истинного.

однако, если вы также можете иметь 1 в результате, то в случае, когда p=1 есть очень маленький шанс, что вы получите ложную!

вот почему вместо деления на MAX_RAND поделить на MAX_RAND+1.0. Также обратите внимание, что я добавил 1.0 вместо 1 чтобы превратить число в a double (в противном случае я могу получить переполнение, если MAX_RAND==INT_MAX)

наконец, вот альтернативная реализация без разделения:

#include <stdlib.h>
bool prob_true(double p){
    return rand() < p * (RAND_MAX+1.0);
}