[C]смоделировать вероятность

stm7868162

Как с помощью rand смоделировать, например, вероятность p=0.007, или p=0.0000000001 (во втором случае меньше, чем 1/RAND_MAX)?
А то что-то я туплю

stm7868162

я имею в виду функцию, которая с вероятностью p выдаёт 1, а с вероятностью (1-p) выдаёт 0

kokoc88

Делить на RAND_MAX нельзя, у тебя получится неравномерное распределение. Для того, чтобы смоделировать маленькую вероятность, надо просто вызывать rand несколько раз. Типа два события с вероятностью 0.1 вместе выполняются с вероятностью 0.01

stm7868162

ну да, я эти общие идеи понимаю, просто торможу, как свести к вероятности p

kokoc88

Тебе нужна вообще произвольная вероятность?

stm7868162

ага, ну т.е. она хранится в double p, подаю эту переменную функции, и эта функция с вероятностью p говорит ok

Helga87

Самый простой способ - написать функцию long_rand:
 

long long_rand
{
   return long)rand * RAND_MAX + (long) rand;
}
  

При необходимости взять большее число вызовов rand до достижения желаемой точности.
После этого, ты сможешь делать:
int isOk(double p)
{
return double)long_rand / long) RAND_MAX) * long)RAND_MAX < p;
}

gopnik1994

что-то типа того:
 
bool RandBool(double prob) {
// RAND_MAX = 100; // говорят в С нельзя менять.
if (prob > 0) {
do {
prob *= RAND_MAX;
if (prob >= 1)
return rand < int(prob + 0.5);
} while (rand == 0);
}
return false;
}

kokoc88

rand == 0 ровно в 1/32768 случаев, совсем не ясна твоя идея.

kokoc88

Разве в твоём примере будет равномерное распределение вероятности?

gopnik1994

rand == 0 ровно в 1/32768 случаев, совсем не ясна твоя идея.
"Типа два события с вероятностью 0.1 вместе выполняются с вероятностью 0.01"
rand == 0 ровно в 1/RAND_MAX случаев, или я путаю?

kokoc88

RAND_MAX не меняется в Си.

gopnik1994

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

kokoc88


double next_prob = prob * RAND_MAX;
if (next_prob >= RAND_MAX)
return rand < prob;

Это условие выполняется только при prob равном единице.

gopnik1994

поправил, теперь вроде должно работать

kokoc88



Разве в твоём примере будет равномерное распределение вероятности?
Будет, но надо к RAND_MAX добавить 1.

kokoc88


prob *= RAND_MAX;
if (prob >= 1)
return rand < prob;

Даже если поправить на RAND_MAX+1, то у тебя при p равном 0.001 условие будет выполняться с вероятностью ~0.000977

gopnik1994

вот прикопался!
это уже тонкости, добавь +1 в нужных местах.
я тут стратегией занимаюсь

kokoc88

Ну заметь, что у Красина стратегическая точность всё-таки повыше.

stm7868162

всем спасибо

gopnik1994

у Красина стратегическая точность всё-таки повыше.
"стратегическая точность" - это как? Эти слова как рядом оказались?
Мой способ - это просто аналитическое расширение его способа. В том смысле, что его способ - есть случай второй итерации моей функции. Причем его способ с делением, а мой - нет.

kokoc88



"стратегическая точность" - это как? Эти слова как рядом оказались?
Мой способ - это просто аналитическое расширение его способа. В том смысле, что его способ - есть случай второй итерации моей функции. Причем его способ с делением, а мой - нет.
Слова рядом оказались, потому что ты написал про стратегию. Твой способ отличается с точки зрения точности решения: до 10% погрешности. Да, твой способ без деления, только у тебя rand вызывается два раза на n-1 итерациях, а там тоже есть деления.

gopnik1994

Слова рядом оказались, потому что ты написал про стратегию.
Стратегия - это web page
только у тебя rand вызывается два раза на n-1 итерациях.
не угадал.

kokoc88

Не угадал чего? Что два раза вызывается - так и есть. А что в rand есть деления... Может и нет, но я не думаю, что ряд сдвигов и перестановка элементов массива в памяти гораздо лучше одного деления. Давай продолжим спор, когда ты напишешь код так, что погрешность твоего метода будет меньше 1%.

gopnik1994

не угадал, что 2 раза вызывается
а ка ты мерял распределение?
или аналитикой вывел?

kokoc88

Сколько же по-твоему раз вызовется rand в твоём коде, если при первой итерации p будет меньше 1.0?

А распределение я никак не мерял, у тебя погрешность в вероятности. Как я сказал, для p = 0.0001 вероятность возврата true будет 0,000092.

gopnik1994

Сколько же по-твоему раз вызовется rand в твоём коде, если при первой итерации p будет меньше 1.0?
один!
ты меня так смутил, что я даже проверил!

kokoc88

Ну вот, вызывается 1 раз и потом ещё 1 раз. Я просто ошибся в том, что написал. Ладно, с этой стороны всё ок. Вернёмся к погрешности...

gopnik1994

может ты тогда поделишься своими выкладками, а то у меня все нормально получается...

gopnik1994

кажись, я понял, что ты имеешь в виду...
щас подумаем...

gopnik1994

хотя нет, не понял

kokoc88

Ну я могу ошибаться. Давай подумаем, ты всегда отсекаешь десятичную часть при сравнении rand < p.
 
Это значит, что при 3.2767 срабатывание будет на числах 0, 1, 2, 3. Эти числа выкидываются с вероятностью ~0,000122; и т.п.

gopnik1994

я сначала подумал об этом, но потом понял, что при округлении или добавлении 0.5 при сравнении оно на самом деле усреднится к 0.
так что правлю код на +0.5...
еще замечания будут?
а сбило меня с толку, что неявное приведение в паскале работает как округление в отличие от С

kokoc88

Я ошибся в выкладках. А предложенное тобою решение только ухудшило ситуацию. Впрочем, отрезая десятичную часть ты никогда не добьёшься стабильно малой погрешности.

gopnik1994

1) вроде ничего не ухудшил
2) я тебя огорчу, но на RAND_MAX=32768 далеко не уедешь... Дискретность останется всегда... В моем примере дискретность остается в точности такая же, как и в rand для p=O(0.1) и скачками уменьшается при p-> 0.
Альтернатива - это написание полностью своего генератора с меньшей дискретностью, чем rand.
Но это совсем другая история, хотя тоже вполне реальная...

kokoc88

1. p = 0.0001, p*MAX=3.2767, rand < 3 в ~0,000092, всё ещё больше 1%
2. Я не требовал убрать дискретность, я просто сравнивал с тем, что у Красина. Для приведённых в первом топике чисел у него погрешность меньше 1%.

gopnik1994

я просто сравнивал с тем, что у Красина. Для приведённых в первом топике чисел у него погрешность меньше 1%.
согласен, это потому что у него всегда юзается 2 rand а уменя не всегда, а только при необходимости "углубления" к нулю. Мою процедуру можно легко заставить делать 2 итерации (чтобы юзалось 2 вызова ранд-а) и тогда точности сравняются.

kokoc88

Ну свяжи и посмотри, что получается. А потом скажи, чем это лучше того, что у Красина?

gopnik1994

лучше тем, что оно может работать и для 1е-10 и для 1е-200

gopnik1994

Ну свяжи и посмотри, что получается
все очень просто:
 
bool RandBool(double prob) {
// RAND_MAX = 100; // говорят в С нельзя менять.
if (prob > 0) {
do {
prob *= RAND_MAX * RAND_MAX;
if (prob >= 1)
return rand*RAND_MAX+rand < int(prob + 0.5);
} while (rand == 0 && rand == 0);
}
return false;
}

rosali

Лучше б рекурсию написали -- сложнее ошибиться.
 
bool f(double p) {
  if (p > 0.1) {
    return rand < RAND_MAX * p;
  } else {
    return f(0.2) && f(p*5);
  }
}

danilov

Если не критично время, то можно по ЦПТ (много раз сгенерить случайное число и нормировать - получим нормальное распределение).
Только нужно знать квантиль нормального распределения.
Оставить комментарий
Имя или ник:
Комментарий: