Как получить случайное число в N-ном деапазоне ? - страница 5

 
Aleksey Rodionov:
А может проще попросить разрабов добавить функцию где можно выбирать диапозон? :) я когда искал в сети интернет эту функцию, то очень много таких тем, значит пользуется популярность rand()

Зачем? От rand() требуется просто быть надежным источником энтропии (случайности) а привести результат к нужному диапазону не сложно.

Alexey Navoykov:

Вот такой код у меня родился.  Сорри за растянутость, но так удобнее читается.

Да, у меня получился попроще)

ulong rand64(ulong ulDiapazone =0)
{
ulong rnd64;
ulong MAX_VALID_RND64 =(0xFFFFFFFFFFFFFFFF - (0xFFFFFFFFFFFFFFFF % Diapazone));

    do
    {
                // сложение бит 15 + 15 + 15 + 15 + 4 =64
        rnd64 =((ulong)rand()|((ulong)rand() << 15)|((ulong)rand() << 30)|((ulong)rand() << 45)|((ulong)rand() << 60));
        
    }while((bool)ulDiapazone && (rnd64 > MAX_VALID_RND64));
    
    if((bool)ulDiapazone)
        return(rnd64 % ulDiapazone);
    
return(rnd64);
}

Странное дело.. но 64-битная версия без лишних припарок даёт практически идеальное распределение (верхний - с хвостом)

pavlick_:
Если тестер с облаками не нужен, то, на мой взгляд, проще написать на стороне, чем мастерить все эти велосипеды. Взять плюсовую https://en.cppreference.com/w/cpp/numeric/random (сомневаюсь, что в мкл появится что-то такого уровня), всё вылизано, без багов. А если хочется, то можно подсунуть свой источник случайности (чего-нибудь из сети дёрнуть, а у некоторых на борту есть ГСЧ), который будет работать с желаемым адаптером обеспечивающим нужное распределение.

Как показали предварительные тесты у MQL-шного rand() очень хорошее распределение.

 
SemenTalonov:

Да, у меня получился попроще)

Но тут встаёт вопрос об эффективности.  На малых диапазонах будет слишком медленно работать, т.к. всегда запрашивает 5 случайных чисел, что избыточно.  Хотя на больших диапазонах наоборот быстрее за счёт сокращения числа проверок. Но с другой стороны, как правило, диапазон мы задаём константами, поэтому все лишние проверки вырезаются на стадии компиляции.

 

Прошлый мой код оказался некорректный. Перемудрил с разрядами.  Вот правильный вариант, а заодно и более лаконичный:

ulong RandomLong(ulong range)
{
 #define _MAXRND(range, rnd_range)  ((rnd_range) - ((rnd_range)-range)%range - 1) 
 #define _RND (ulong)rand()
  ulong rnd, max, const bit=1;
  if (range <= bit<<15) { if (!range) return 0;  max=_MAXRND(range, 1<<15);  while((rnd=_RND) > max);  return rnd%range; }
  if (range <= bit<<30) { max=_MAXRND(range, bit<<30);  while((rnd=(_RND | _RND<<15)) > max);  return rnd%range; }
  if (range <= bit<<45) { max=_MAXRND(range, bit<<45);  while((rnd=(_RND | _RND<<15 | _RND<<30)) > max);  return rnd%range;  }
  if (range <= bit<<60) { max=_MAXRND(range, bit<<60);  while((rnd=(_RND | _RND<<15 | _RND<<30 | _RND<<45)) > max);  return rnd%range; }
                  else  { max=_MAXRND(range, bit<<64);  while((rnd=(_RND | _RND<<15 | _RND<<30 | _RND<<45 | _RND<<60)) > max);  return rnd%range; }
 #undef _RND               
 #undef _MAXRND
}
 
Alexey Navoykov:

Но тут встаёт вопрос об эффективности.  На малых диапазонах будет слишком медленно работать, т.к. всегда запрашивает 5 случайных чисел, что избыточно.  Хотя на больших диапазонах наоборот быстрее за счёт сокращения числа проверок. Но с другой стороны, как правило, диапазон мы задаём константами, поэтому все лишние проверки вырезаются на стадии компиляции.

Совершенно верно. И эффективности, и здравого смысла. Ведь в подавляющем большинстве случаев применения ГПСЧ, хватит и 15-ти бит стандартного rand(). А теперь, после чистки "хвостов", он совершенно безопасен.

Но иметь под рукой, наготове, такой 64-битный KING SIZE, в нашем деле совершенно не будет лишним.


С Наступающим, господа Исследователи неслучайных случайностей! 

 
SemenTalonov:

Как показали предварительные тесты у MQL-шного rand() очень хорошее распределение.

Это хорошо, конечно. Но не всегда нужно равномерное распределение, к источнику случайности необходима куча адаптеров, может понидобится такое:

0: ****
1: *
2: *
3: ****

или такое

0: ***********
1: ***

Нужна будет единичка с вероятностью 23.57%, и начнутся велосипеды, баги.

ЗЫ: не подумайте, что я не знаю как написать на базе голого rand().

 

Бумс...

void OnStart(){
   Print(rndr(1,3));
}

int rndr(int mn,int mx,bool inclusive=true){
   return(mn+rndn(mx-mn+(int)inclusive));
}

int rndn(int n){
   if(n>32768 || n<0){
      return(-1);
   }
   int r;
   while((r=MathRand())<32768%n);
   return(r%n);
}

Вроде не ошибся?

 

А вот два варианта long (просто long без диапазона):

ulong RndLong2(){

   ulong l1=MathRand();//x[0];// 
   ulong l2=MathRand();//x[1];//
   ulong l3=MathRand();//x[2];//
   ulong l4=MathRand();//x[3];//
   
   l2=l2<<16;
   l3=l3<<32;
   l4=l4<<48;   
   
   return(l1|l2|l3|l4);
}

// с юнионом
ulong RndLong1(){
   union u1{
      int u;
      char c[4];
   } u;
   union u2{
      ulong u;
      char c[8];
   } r;
   r.u=0;
   for(int i=0;i<4;i++){
      u.u=MathRand();//x[i];
      r.c[i*2]=u.c[0];
      r.c[i*2+1]=u.c[1];
   }
   return(r.u);   
}
 

Подыму ветку, ибо вижу тут умных людей.

Ситуация такая, нужно мне при инициализации рандомить настройки - выяснилось, что комбинации очень сильно повторяются, т.е. допустим мне нужно получить случайное значение от 0 до 99, при этом получаю 6 раз его, и из 1000 случаев в 11 я имею одинаковую комбинацию выпадания последовательно этих 6 значений - как сделать реальный рандом при инициализации? Может как то привязаться к локальным часам или ещё как? Использовал разные тут предложенные функции (нужна без dll).

Визуализация повторений


Прикладываю код советника, который при оптимизации выдает значение случайных генераторов.

#property copyright "Copyright 2022, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

ulong Rand=0;
input int Brut=0;
//+------------------------------------------------------------------+
//| Initialization function of the expert                            |
//+------------------------------------------------------------------+
int OnInit()
{
      Random_Setup();
      return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Deinitialization function of the expert                          |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{

}
//+------------------------------------------------------------------+
//| "Tick" event handler function                                    |
//+------------------------------------------------------------------+
void OnTick()
{

}
//+------------------------------------------------------------------+
//| Обработчик события окончания тестирования                        |
//+------------------------------------------------------------------+
double OnTester()
{
return (double)Rand;
}

//+------------------------------------------------------------------+
//|Генератор входных настроек случайным образом по отобранным ранее комбинациям
//+------------------------------------------------------------------+
void Random_Setup()
{
   ulong N_Group=0;
   for(int i=0; i<6; i++)
   {
      N_Group=RandomLong(99);
      Rand=Rand+N_Group*(ulong)MathPow(100,(i));
      Print("N_Group=",N_Group," Rand=",Rand);
   }
}

//+------------------------------------------------------------------+
//|Определяем комбинацию случайным образом
//+------------------------------------------------------------------+
/*
int RandomInteger(int max_vl)
{
   return (int)MathFloor((MathRand()+MathRand()*32767.0)/1073741824.0*max_vl);  //случайное Int от 0 до  1073741824
}
*/

ulong RandomLong(ulong range)
{
 #define _MAXRND(range, rnd_range)  ((rnd_range) - ((rnd_range)-range)%range - 1) 
 #define _RND (ulong)rand()
  ulong rnd, max, const bit=1;
  if (range <= bit<<15) { if (!range) return 0;  max=_MAXRND(range, 1<<15);  while((rnd=_RND) > max);  return rnd%range; }
  if (range <= bit<<30) { max=_MAXRND(range, bit<<30);  while((rnd=(_RND | _RND<<15)) > max);  return rnd%range; }
  if (range <= bit<<45) { max=_MAXRND(range, bit<<45);  while((rnd=(_RND | _RND<<15 | _RND<<30)) > max);  return rnd%range;  }
  if (range <= bit<<60) { max=_MAXRND(range, bit<<60);  while((rnd=(_RND | _RND<<15 | _RND<<30 | _RND<<45)) > max);  return rnd%range; }
                  else  { max=_MAXRND(range, bit<<64);  while((rnd=(_RND | _RND<<15 | _RND<<30 | _RND<<45 | _RND<<60)) > max);  return rnd%range; }
 #undef _RND               
 #undef _MAXRND
}
 

Интересно, если средствами MQL получение случайного числа не устраивает, то почему бы ни сделать функцию на другом языке программирования, воткнуть её в dll и подключить длл-ку к коду советника/индикатора/скрипта?

Мне когда не хватает возможностей MQL, я так и делаю. Работает на ура.

 
Vitaly Murlenko #:

Интересно, если средствами MQL получение случайного числа не устраивает, то почему бы ни сделать функцию на другом языке программирования, воткнуть её в dll и подключить длл-ку к коду советника/индикатора/скрипта?

Мне когда не хватает возможностей MQL, я так и делаю. Работает на ура.

Мне для маркета надо - там нельзя dll использовать. Ну и не умею я на другом языке то ваять, увы.

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