How does MathRand() generate values? - page 2

 
yu-sha:

Please tell me how MathRand() gets values.

Can we expect uniform distribution of MathRand() in declared range?

here is one example, of course there are other, more complex algorithms...

source rand.c :

/***
*rand.c - random number generator
*
*       Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved.
*
*Purpose:
*       defines rand(), srand() - random number generator
*
*******************************************************************************/

#include <cruntime.h>
#include <mtdll.h>
#include <stddef.h>
#include <stdlib.h>

#ifndef _MT
static long holdrand = 1 L;
#endif  /* _MT */

/***
*void srand(seed) - seed the random number generator
*
*Purpose:
*       Seeds the random number generator with the int given.  Adapted from the
*       BASIC random number generator.
*
*Entry:
*       unsigned seed - seed to seed rand # generator with
*
*Exit:
*       None.
*
*Exceptions:
*
*******************************************************************************/

void __cdecl srand (
       unsigned int seed
       )
{
#ifdef _MT

       _getptd()->_holdrand = (unsigned long)seed;

#else  /* _MT */
       holdrand = (long)seed;
#endif  /* _MT */
}


/***
*int rand() - returns a random number
*
*Purpose:
*       returns a pseudo-random number 0 through 32767.
*
*Entry:
*       None.
*
*Exit:
*       Returns a pseudo-random number 0 through 32767.
*
*Exceptions:
*
*******************************************************************************/

int __cdecl rand (
       void
       )
{
#ifdef _MT

       _ptiddata ptd = _getptd();

       return( ((ptd->_holdrand = ptd->_holdrand * 214013 L
           + 2531011 L) >> 16) & 0x7fff );

#else  /* _MT */
       return(((holdrand = holdrand * 214013 L + 2531011 L) >> 16) & 0x7fff);
#endif  /* _MT */
}
 

A RNG function is required with the number Int from 0 to any value.

Since the maximum value of Int =2,147,483,647, we calculate up to it.

We have obtained this function. I think the distribution is uniform.

int RandomInteger(int max_vl){//случайное Int от 0 до  Max Int
        //srand(0);//если нужна повторяемость.  MathSrand(GetTickCount()) если нужна неповторяемость
        int r=MathRand();// от 0 до 32767.
        double k=32767.0;
        if(max_vl>32767){
                r=r+MathRand()*32767;//0...32767 + 0.. 32767*32767(с шагом 32767)  max=1073709056 > 1 mlrd
                k=k*k;
                if(max_vl>1073709056){// int type max alue =2 147 483 647 > 2 mlrd
                        r=r*2+MathRand()%2;//0...2 147 483 647 > to max int number c шагом 2 + (0 или 1)
                        k=k*2;
                }
        }
        return (int)MathFloor(r/k*max_vl);
}
 
The article has a generator to 4294967295
 
Rorschach:
The article has a generator up to 4294967295

Alglib SB has a high precision oscillator

UPD: I tried ithttps://www.mql5.com/ru/forum/324066#comment_13500222 , it seems to work, but there is no documentation for Alglib in MQL5, you should read it on the Alglib website

 
Rorschach:
The article has a generator to 4294967295

Thanks, I compared it in terms of computational speed.
My function on standard rand() turned out to be 2 times slower. Although the code seemed much simpler...


 
Igor Makanu:

There is a high precision generator in Alglib

UPD: I tried ithttps://www.mql5.com/ru/forum/324066#comment_13500222 , it seems to work, but there is no documentation for Alglib in MQL5, you should read it on the Alglib website

I saw it but I want it without alglib. In addition, that function has a lot of */%. I have not compared its speed since it is obviously slower. The generator from the article works with bit shifts - it's faster.

 

Rewrote my function to optimise the speed:

int RandomInteger(int max_vl){return (int)MathFloor((MathRand()+MathRand()*32767.0)/1073741824.0*max_vl);}//случайное Int от 0 до  Max Int
The distribution turned out to be uniform. See images of the experiment in the blog https://www.mql5.com/ru/blogs/post/735953

I rewrote the RNG from the article.
I discarded unnecessary things, and this is what I got:

//если из define переместить в код RNDUint, то скорость работы увеличится на 30% для 10 млн повторов с 600 мс до 850 мс
#define  xor32  xx=xx^(xx<<13);xx=xx^(xx>>17);xx=xx^(xx<<5)
#define  xor128 t=(x^(x<<11));x=y;y=z;z=w;w=(w^(w>>19))^(t^(t>>8))
#define  inidat x=123456789;y=362436069;z=521288629;w=88675123;xx=2463534242

class RNDUint{
protected:
   uint      x,y,z,w,xx,t;
public:
        RNDUint(void){inidat;};
        ~RNDUint(void){};
   uint      Rand()    {xor128;return(w);};//равномерное распределение на отрезке [0,UINT_MAX=4294967295].
   double    Rand_01() {xor128;return((double)w/UINT_MAX);};//равномерное распределение на отрезке [0,1].
   void      Reset()   {inidat;};//сброс всех исходных значений в первоначальное состояние.
   void      SRand(uint seed)  {//установка новых исходных значений генератора.seed= [0,UINT_MAX=4294967295]. При seed=0 функция меняет начальные значения случайным образом.
      int i;if(seed!=0){xx=seed;}for(i=0;i<16;i++){xor32;}xor32;x=xx;xor32;y=xx;xor32;z=xx;xor32;w=xx;for(i=0;i<16;i++){xor128;}
   };
};

Distribution turned out to be equal too.

I compared speed of both functions, original from article and simple MathRand():


The original from the article rnd.Rand_01() - 602 ms
Shortened according to the article rnu.Rand_01() - 596 ms
My optimized version of RandomInteger() - 840 ms (old version 1200 ms, i.e. 25% faster)
Just by MathRand() - 353 ms (fastest, but distribution will be uneven. If the range of numbers required is greater than 32767, the result will be skipped. If less than 32767, for example i=31111. then rounding will be more frequent to some points).

Take advantage)
Rand 0 ... Max Int с равномерным распределением
Rand 0 ... Max Int с равномерным распределением
  • www.mql5.com
Потребовалась функция ГСЧ с гнерацией числа Int от 0 до любого значения.Получилась такая функция. Думаю распределение получилось равномерным. int RandomInteger(int max_vl){return
 
elibrarius:
Interesting. Found another random in the standard library, but it's unlikely to be better.
 

Why complicate things so much?

You can do it this way (roughly speaking):

if (MathRand()%100>50) => Buy

if (MathRand()%100<50) => Sell

And if you want to play around or see what it shows, you can do this:

int x=1;

if (MathRand()%100>50) x=1;

if (MathRand()%100<50) x=2;

Comment(x);

and see how it changes values.

 
elibrarius:

I have rewritten my function to optimize speed:

The distribution is even. See images of the experiment on the blog https://www.mql5.com/ru/blogs/post/735953

I rewrote the RNG from the article.
I discarded unnecessary things and that's what I got:

Distribution turns out to be uniform too.

I compared it with the distribution from the help, I don't see any difference