Comment MathRand() génère-t-il des valeurs ? - page 3

 

J'ai ajoutéMathRandomUniform à mon script pour comparaison.
J'ai réglé la génération de points à 1000000. Pour estimer la distribution, j'affiche les 1000000 points à l'écran sous la forme d'un carré de 1000*1000. Plus vous touchez un point, plus sa couleur est vive.

J' ai défini 10 millions de répétitions du RNG, donc en moyenne chaque point devrait être touché 10 fois.

Voici les résultats :
RND :


Ma variante de RandomInteger :


Sur MathRand() :


À l'adresse MathRandomUniform() :


Les deux premiers RND sont tout à fait pairs, les 3 et 4 ont des lacunes, c'est-à-dire qu'ils ne sont pas pairs.
Les sauts sont dus à la résolution MathRand = 32767. Avec un multiplicateur de 1000000, nous obtiendrons des sauts de 1000000/32767=30 points. MathRandomUniform est similaire par image, probablement, il a les mêmes 30 sauts.

Une autre variante. Fixons le nombre maximal à 30000.
RND et RandomInteger sont égaux, comme s'ils étaient un million .MathRand et MathRandomUniform ressemble à ceci (avec un morceau agrandi) :


Il n'y a pas de lacunes (points noirs jusqu'à la position 30000). Mais certaines sont nettement plus lumineuses. Il s'agit d'un arrondi irrégulier de 30000/32767. Chaque 11ème point reçoit deux fois plus de coups.

Quelque chose d'uniforme peut être obtenu à partir de MathRand à un maximum de 3000... 4000. Voici une variante élargie pour 3500 :


Les deux premières variantes, lorsqu'elles s'approchent du nombre maximal de 100 millions pourRandomInteger (qui a une résolution d' environ 1 milliard) et de 400 millions à une résolution de 4 milliards pour RND, - commenceront également à se répartir de manière inégale en raison des arrondis.

J'ai joint le fichier, vous pouvez répéter l'expérience.
J'ai décidé d'utiliser ma propre fonction pour moi, elle est 25% plus lente que RND mais plus compacte et plus claire, je peux augmenter la résolution jusqu'à 32767 fois plus, voir le code dans le blog.


Note :
Le développeur RND de l'article a souligné que

A seed=0, la fonction change les valeurs initiales de façon aléatoire.

A chaque redémarrage, je mets seed=0, mais l'image avec les distributions ne change pas aux redémarrages. C'est-à-dire que l'affirmation est incorrecte. On ne voit pas non plus dans le code pourquoi cela devrait devenir aléatoire. Ainsi, pour initialiser de manière aléatoire, seed doit être défini comme un nombre aléatoire, par exemple seed=GetTickCount();

Pour la fonction RandomInteger(), on observe une redistribution des points lors des redémarrages. Si srand(0) ; est défini, la distribution commence également à se répéter lors des redémarrages. Donc pour que cette fonction s'initialise de façon aléatoire, je dois soit ne pas appeler srand, soit utiliser MathSrand(GetTickCount()) avec timestamp également.

Dossiers :
 

Gardez à l'esprit que xor128 passe des tests d'aléatoire spéciaux, et qu'avec le rand standard, il peut être

Forum sur le trading, les systèmes de trading automatisés et les tests de stratégie

L'apprentissage automatique en trading : théorie, pratique, trading et au-delà

Rorschach, 2020.04.19 22:18

Je suis un bricoleur, j'ai cassé le 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 voie : w doit être une puissance de 2, k est un multiple de 4

Méthode 2 : décommenter srand

La méthode 2 devrait également fonctionner sur le vortex de Mersen.

 
Rorschach:

Notez que xor128 passe des tests spéciaux d'aléatoire, et avec un rand standard il peut être



Vous affichez chaque 16ème appel de rand. Une sorte de modèle de cette périodicité apparaît.
J'utilise tous les appels consécutifs de 2 dans chacun. Visuellement, d'après mes photos, je ne vois pas de différence avec xor128 pour 10 millions de répétitions.
 
Rorschach:

Notez que xor128 passe des tests spéciaux d'aléatoire, et avec un rand standard il peut être


J'ai essayé de substituer ma propre fonction et xor128 dans votre fonction

#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() a aussi quelques divisions.
C'est mieux avec le xor128, mais il y a des bandes :

Je ne suis pas sûr qu'en utilisation normale (pas 1 sur 16) ces lignes dans RandomInteger() aient un quelconque effet... Et ce qu'ils veulent dire n'est pas clair...

Mais je pense que le xor128 est plus fiable.

 
Rorschach:

Notez que xor128 passe des tests spéciaux d'aléatoire, et avec un rand standard il peut être


Vous avez le code de Mersen ? Je l'ai fait sur OpenCL quelque part mais je n'ai pas eu le temps de le porter sur MQL5. Il serait intéressant de comparer.

La méthode 2 devrait également fonctionner sur le vortex de Mersen.


 
Rashid Umarov:

Vous avez le code de Mersen ? Je l'ai fait sur OpenCL quelque part mais je n'ai pas eu le temps de le porter sur MQL5. Il serait intéressant de comparer.

Ici, je ne l'ai pas utilisé moi-même.

 
elibrarius:

Vous affichez chaque 16ème appel rand. Une sorte de modèle de cette périodicité apparaît.
J'utilise tous les appels consécutifs de 2 dans chacun. Visuellement, d'après mes photos, je ne vois pas de différence avec xor128 pour 10 millions de répétitions.

Je ne sais pas quel est votre objectif d'utilisation, je vous préviens simplement qu'il peut y avoir des surprises.

 
Rorschach:

Ici, je ne l'ai pas utilisé moi-même.

Merci ! Le code s'est avéré être plus gros que sur OpenCL. J'essaierai de le découvrir un jour.

 

un coup amical sur ter.ver, la magie des entiers, les arrondis, l'arithmétique modulaire et les astuces du double :-)

si f(x) : : entier uniformément distribué sur (0;N], cela ne signifie pas que g(x)=N/(double)f(x) sera uniformément distribué sur (0;1] et passera également tous les tests.

Il en va de même pour g(x) = f(x) mod M , à l'exception rare de N mod M = 0.

PS/ d'ailleurs et g(x)=f(x)/(double)N ne sera pas non plus uniforme. Il y aura des points focaux de division. C'est-à-dire que les tracés présenteront du moiré.

PPS/ pour un "test" visuel de l'aléatoire, en plus de l'équerre modulo, des variantes de "l'escargot d'Ulam" sont appliquées.

 
Rorschach:

Ici, je ne l'ai pas utilisé moi-même.

Mesuré les performances de CRandomMersenne et CRandomMother à partir de ce code. Ils sont 3 fois plus lents que le xor128. Ce n'est pas très satisfaisant. Mais d'après votre code, où vous avez cassé le GSF, ils semblent meilleurs que xor128 (sans la barre verticale).