How does MathRand() generate values? - page 3

 

I addedMathRandomUniform to my script for comparison.
I set point generation to 1000000. To estimate distribution, I display all 1000000 points on the screen as a 1000*1000 square. The more times you hit a point, the brighter its colour.

I have set 10 million repetitions of RNG, so on the average each dot should be hit 10 times.

Here are the results:
RND:


My variant of RandomInteger:


On MathRand():


At MathRandomUniform():


The first two RNDs are quite even, 3 and 4 have gaps, i.e. they are not even.
The skips are due to MathRand resolution = 32767. At a multiplier of 1000000 we will get skips 1000000/32767=30 points. MathRandomUniform is similar by image, probably, it has the same 30 sk ips.

Another variant. Let's set the maximal number 30000.
RND and RandomInteger are equal, as if they were a million .MathRand and MathRandomUniform looks like this (with enlarged chunk):


There are no gaps (black dots up to position 30000). But some are noticeably brighter. This is an uneven rounding of 30000/32767. Every 11th dot gets twice as many hits.

Something uniform can be obtained from MathRand at a maximum of 3000... 4000. Here is an enlarged variant for 3500:


The first two variants when approaching the maximum number to 100 million forRandomInteger (which has resolution about 1 billion) and 400 million at 4 billion resolution for RND, - will also start to distribute unevenly due to rounding.

I've attached the file, you may repeat the experiment.
I've decided to use my own function for myself, it's 25% slower than RND but more compact and clearer, I can increase resolution up to 32767 times more, see code in the blog.


Note:
The RND developer from the article pointed out that

At seed=0 the function changes initial values randomly.

At each restart, I set seed=0, but the picture with distributions does not change at restarts. I.e. the statement is incorrect. You can't see from the code why it should become random either. So, to initialize randomly, seed must be set to a random number, for example seed=GetTickCount();

For RandomInteger() function, we see redistribution of points on restarts. If srand(0); is set, the distribution also starts repeating on restarts. So for this function to initialize randomly, I need either don't call srand, or use MathSrand(GetTickCount()) with timestamp too.

Files:
 

Keep in mind that xor128 passes special randomness tests, and with standard rand can be

Forum on trading, automated trading systems & strategy testing

Machine Learning in Trading: Theory, Practice, Trading and Beyond

Rorschach, 2020.04.19 22:18

I am a handyman, i broke the RSCH(((

#include <Canvas\Canvas.mqh>
void OnStart()
  {CCanvas C;
   int h=1024;
   int w=2048;
   C.CreateBitmapLabel("11",100,100,w,h);
   for(int y=0;y<h;y++)
     {//srand(GetMicrosecondCount());
      for(int x=0;x<w;x++)
        {uchar c=0;
         for(int k=0;k<16;k++)
           {c=uchar(255.*rand()/32767.);
           }
         C.PixelSet(x,y,ARGB(255,c,c,c));
        }
     }
   C.Update();

1 way: w must be a power of 2, k is a multiple of 4

Way 2: uncomment srand

Method 2 should also work on the Mersen vortex

 
Rorschach:

Note that xor128 passes special randomness tests, and with a standard rand it can be



You display every 16th rand call. Some sort of pattern from this periodicity shows up.
I am using all consecutive calls of 2 in each. Visually, from my pictures, I don't see any difference with xor128 for 10 million repetitions.
 
Rorschach:

Note that xor128 passes special randomness tests, and with a standard rand it can be


I tried to substitute my own function and xor128 into your function

#include <Canvas\Canvas.mqh>
void OnStart()
  {CCanvas C;
  RND rn;   rn.SRand(0);
   int h=1024;
   int w=2048;
   C.CreateBitmapLabel("11",100,100,w,h);
   for(int y=0;y<h;y++)
     {//srand(GetMicrosecondCount());
     rn.SRand(GetMicrosecondCount());
      for(int x=0;x<w;x++)
        {uchar c=0;
         for(int k=0;k<16;k++)
           //{c=uchar(255.*rand()/32767.);}
           //{c=uchar(255.*RandomInteger(1073741824)/1073741824.0); }
           {c=(uchar)(255.0*rn.Rand_01()); }
         C.PixelSet(x,y,ARGB(255,c,c,c));
        }
     }
   C.Update();
   }
  
   int RandomInteger(int max_vl){return (int)MathFloor((MathRand()+MathRand()*32767.0)/1073741824.0*max_vl);}//случайное Int от 0 до  1073741824


//если из define переместить в код RNDUint, то скорость работы увеличится на 30% для 10 млн повторов с 600 мс до 850 мс. Это почти как RandomInteger()

#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 RND{
protected:
   uint      x,y,z,w,xx,t;
public:
      RND(void){inidat;};
    ~RND(void){};
   uint      RandMaxUI(uint max_v)   {xor128;return((uint)MathFloor((double)w/UINT_MAX*max_v));};//равномерное распределение на отрезке [0,max_v]. uint
   int       RandMaxI(int max_v)     {xor128;return((int) MathFloor((double)w/UINT_MAX*max_v));};//равномерное распределение на отрезке [0,max_v]. int
   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;}
   };
};


RandomInteger() has some divisions too.
Better with xor128, but there is some banding:

I'm not sure that in normal use (not 1 of 16) these dashes from RandomInteger() will have any effect... And it's not clear what they mean...

But I think xor128 is safer to use.

 
Rorschach:

Note that xor128 passes special randomness tests, and with a standard rand it can be


Do you have Mersen's code? I had it on OpenCL somewhere but haven't got around to porting it to MQL5. It would be interesting to compare.

Method 2 should also work on Mersen's vortex


 
Rashid Umarov:

Do you have Mersen's code? I had it on OpenCL somewhere but haven't got around to porting it to MQL5. It would be interesting to compare.

Here, I haven't used it myself.

 
elibrarius:

You display every 16th call rand. Some sort of pattern from this periodicity shows up.
I am using all consecutive calls of 2 in each. Visually, from my pictures, I don't see any difference with xor128 for 10 million repetitions.

I don't know what your purpose of use is, just a warning that there may be surprises.

 
Rorschach:

Here, I haven't used it myself.

Thanks! The code turned out to be bigger than on OpenCL. I'll try to figure it out sometime.

 

a friendly hit on ter.ver, the magic of integers, rounding, modular arithmetic and the tricks of double :-)

if f(x) :: integer uniformly distributed on (0;N], it does not mean that g(x)=N/(double)f(x) will be uniformly distributed on (0;1] and also will pass all tests.

About the same about g(x) = f(x) mod M , with rare exception N mod M = 0.

PS/ by the way and g(x)=f(x)/(double)N will not be uniform either. There will be focal points of division. That is, the plots will show moiré.

PPS/ for a visual "test" for randomness, in addition to the modulo blunt square, variations of the "Ulam snail" are applied

 
Rorschach:

Here, I haven't used it myself.

Measured the performance of CRandomMersenne and CRandomMother from this code. They are 3 times slower than xor128. This is not very satisfying. But according to your code, where you broke the GSF, they look better than xor128 (without the vertical bar).