2013-12-01 7 views
4

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

+2

Какой _exactly_ вы пробовали? – jogojapan

+0

http://stackoverflow.com/questions/3771551/how-to-generate-a-boolean-with-p-probability-using-c-rand-function – jogojapan

ответ

10

Если вы» d хотел бы сделать это на 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 с заданной вероятностью.Вероятность того, что принимает это вероятность возвращения верно, так это именно то, что вам нужно:

#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++, второе издание, автор Nicolai Josuttis, отличная справочная работа.)

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

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

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

+3

['std :: bernoulli_distribution'] (http://en.cppreference.com/w/cpp/numeric/random/bernoulli_distribution) будет делать именно то, что ему нужно, лучше, чем std :: uniform_real_distribution. – Blastfurnace

+0

@Blastfurnace: Вы правы. Как-то я пропустил это. Я отредактирую выше. –

3
#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 до 0.634 - и проверьте, упал ли результат в этой области.

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

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

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

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

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

Должно ли вы называться 'rand()'? –

+0

@BitFiddlingCodeMonkey Duh! Исправление:/ – rabensky

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