Функция ReQuote. Вопрос к математикам

 

Написал простенькую функцию для имитации реквотов.

Суть в следующем, в параметре передаём функции процент вероятности реквота, а

она подбрасывает монетку и сообщает был реквот или нет. Для равномерного распределения вероятностей

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

корнем синусной функции - то, реквот. Странное дело, до 50% работает нормально, а выше процент реквотов

снижаеться :( Почему ? Скрипт ниже

//+------------------------------------------------------------------+
//|                                                          tmp.mq4 |
//|                                                           MaStak |
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright "MaStak"
#property link      ""
#define Pi 3.1415926535897932384626433832795
//+------------------------------------------------------------------+
//| script program start function                                    |
//+------------------------------------------------------------------+
int start(){
MathSrand(MathMod(GetTickCount(),32767));
int k;
for(int c=0;c<100;c++)
        if(Requote(50))k++;
Comment(c+" - "+k);
return(0);}
//+------------------------------------------------------------------+
bool Requote(double Percent){
bool ret=false;
double RND=MathRand();
if(RND<1)return(ret);
double y=MathAbs(MathSin((327.67*Percent*Pi*RND)/32767.0)*100.0);
if(y<1.0)ret=true;
return(ret);}
//-------------------------------------------------------------------+
 
MaStak >>: Для равномерного распределения вероятностей

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

корнем синусной функции - то, реквот.

Что-то ты намудрил тут, MaStak. У тебя получается, во-первых, что если в функции Requote() функция MathRand() генерит нуль, то реквоты нет. Но вероятность генерации нуля очень маленькая (1/32768), т.е. почти нулевая. Это условие выполняется крайне редко, т.е. его можно и не учитывать при твоей логике.

Во всех остальных случаях реквота генерится, только если |sin(0.01*Percent*Pi*RND)| < 0.01. Почему Percent внутри функции синуса? Значение Percent при большом количестве попыток влияет на частоту реквот не так, как ты хотел. При Percent = 100 у тебя будет совсем не 100% реквот. Если ты хочешь, чтобы реквота генерилась с частотой Percent, не надо мудрить, и проще всю функцию Requote() заменить вот такой:

bool Requote( double Percent )
{
   if( MathRand() < Percent * 32.768 - 1 ) return( true );
   else                                    return( false ); 
}

Кстати, в CodeBase есть статья с готовым алгоритмом тестирования реквот, опубликованная больше двух лет назад. Смотри здесь.

 

Привет, Mathemat. Спасибо, что заглянул.

Попробую представить идею на картинках. Percent задаёт период/частоту выборки(?).

Допустим ГСЧ выбрасывает числа из диапазона 1-100, 0 игнорируем.

Тогда, при Percent=1, функция примет вид

Т.е. Requote=true, если выпадет 100.

Если Percent=3, то Requote=true если выпадет 33 или 66 или 100.

Если Percent=10, то реквот выпадет на числах 10,20,30,40,50,60,70,80,90,100.


Если Percent=100, то частота функции возрастёт на столько что она пройдёт через все числа диапазона.


Ты в своей функции задаёшь диапазон, а я конкретные числа равномерно распределённые по всему диапазону.

Я думал так будет лучше/справедливей.

 

Горе от ума)

bool fRandomEvent(double aProbability=0.5){
   double tRnd=MathRand();
   tRnd/=32768;
   return(tRnd<aProbability);
}
 
наверно ) пора в отпуск
 

MaStak, я твой замысел понял, хотя и не сразу. Давай посмотрим несколько частных случаев.

Скажем, при Percent = 100 для реквоты нужно, чтобы |sin(Pi*RND)| < 0.01. Фактически так оно и будет, т.к. RND - целое число всегда. Все получается.

А если Percent = 60? Тогда условие реквоты - это |sin(0.6*Pi*RND)| < 0.01. Грубо говоря, если 3/5*RND - целое. Это означает, что RND обязано делиться на 5 и никак иначе. Получается, что это только пятая часть от всех чисел, а не 3/5, как ты хотел. Я, правда, не учел тонкого эффекта, связанного с тем, что 3/5*RND должно быть почти целым (у тебя ж не в точности нуль синуса должен быть, а отличие от него на небольшую величину не более 0.01). Но он именно тут не играет роли. Теперь - гораздо более сложный пример. Следи за моими руками и не расслабляйся.

Если Percent = 33, аналогично выходит, что 33/100*RND должно быть почти целым. Если бы мы не учитывали тонкий эффект, то получилось бы, что RND должно делиться на 100, т.е. реквот вроде бы только один процент. С учетом эффекта получится значительно больше. Почему? Если RND = 500, то это явная реквота. Но она останется реквотой и при RND = 497, т.к. 33/100*497 = 33/100*(500-3) = 165 - 99/100 = 164+1/100. Подставляем в функцию синуса, умножая на Pi, и получаем: sin((164+1/100)*Pi) = sin(Pi/100) < 0.01!

Та же фигня будет получаться при всех числах вида 100*N+3, т.к. 33/100*(100*N+3) = целое + 99/100 = другое целое - 1/100. Синус такого аргумента, умноженного на Pi, тоже по модулю меньше 0.01.

Получилось, что реквоты будут при всех вида RND =100N, 100*N +- 3. Это примерно 3 процента. Других случаев реквот вроде бы нет. Но вышло все-таки гораздо меньше, чем ты хотел.

Короче, при твоем алгоритме ты наступаешь на территорию высшей арифметики, которая совсем не такая "непрерывная", как кажется. Надеюсь, объяснил доступно.

P.S. Я лажанулся именно для случая Percent=33 (арифметические ошибки у меня). Там реквот действительно только 1 процент. Но рассуждения, аналогичные зачеркнутым, были бы верны, если бы Percent был равен, скажем, 33.3. Там вообще легко было бы запутаться, т.к. пришлось бы решать несколько уравнений в целых числах.

 

Еще одна:

double fRandomValue(double aK=0.7){
   double tValue=MathRand();
   return(MathExp(-MathPow((tValue/32767.0-0.5)*8.0*MathArctan(1)*aK,2)));
}

На пике значение 1.

 

Mathemat, давай тогда смотреть на знаки :)

bool xRequote(double Percent){
bool ret=false;
double RND=MathRand();
if(RND<1)return(ret);

double y1=MathSin(327.68*Percent*Pi*RND/32768.0);
double y2=MathSin(327.68*Percent*Pi*(RND+1)/32768.0);

if((y1>0 && y2<0) || (y1<0 && y2>0))ret=true;
return(ret);}

Проверил, работает на всех кроме 100%.

Я ещё както пропустил, можно же проверять делиться ли нацело RND на шаг

bool sRequote(double Percent){
bool ret=false;
double Step=32768/(Percent*327.68);
double RND=MathRand();
if(MathMod(RND,Step)==0)ret=true;
return(ret);}

Но при таком варианте работает только до 50%, дальше 1>Step<2. Округления наверно не хватает.

Попробую ещё 2 функцию Integer`a понять.

 

Вот статейка есть - http://www.nuru.ru/teorver/025.htm. У меня примерно то что в ней, только коэффиценты подобрал, так чтобы было приятно глазу и пик был на единице.

 

MasTak, я попытался проанализировать твои функции теоретически и выявил некоторые подводные камни. Наверно, проще было бы сделать это практически - просто взять и проверить. Но в любом случае и функции Integer'a, и моя собственная гораздо прозрачнее, чем твои синусоидальные.

Причина обращения: