¿Cómo genera MathRand() los valores? - página 3

 

He añadidoMathRandomUniform a mi script para comparar.
He puesto la generación de puntos a 1000000. Para estimar la distribución, muestro los 1000000 puntos en la pantalla como un cuadrado de 1000*1000. Cuantas más veces golpees un punto, más brillante será su color.

He establecido 10 millones de repeticiones de RNG, por lo que en promedio cada punto debe ser golpeado 10 veces.

Aquí están los resultados:
RND:


Mi variante de RandomInteger:


En MathRand():


En MathRandomUniform():


Las dos primeras RND son bastante parejas, la 3 y la 4 tienen huecos, es decir, no son parejas.
Los saltos se deben a la resolución de MathRand = 32767. Con un multiplicador de 1000000 obtendremos saltos 1000000/32767=30 puntos. MathRandomUniform es similar por imagen, probablemente, tiene los mismos 30 saltos.

Otra variante. Fijemos el número máximo en 30000.
RND y RandomInteger son iguales, como si fueran un millón .MathRand y MathRandomUniform tiene este aspecto (con el trozo ampliado):


No hay huecos (puntos negros hasta la posición 30000). Pero algunos son notablemente más brillantes. Se trata de un redondeo desigual de 30000/32767. Cada 11º punto recibe el doble de impactos.

Se puede obtener algo uniforme de MathRand a un máximo de 3000... 4000. Aquí hay una variante ampliada para 3500:


Las dos primeras variantes cuando se acercan al número máximo a 100 millones paraRandomInteger (que tiene resolución alrededor de 1 mil millones) y 400 millones a 4 mil millones de resolución para RND, - también comenzará a distribuir de manera desigual debido al redondeo.

Te adjunto el archivo, puedes repetir el experimento.
He decidido usar mi propia función, es un 25% más lenta que RND pero más compacta y clara, puedo aumentar la resolución hasta 32767 veces más, ver código en el blog.


Nota:
El desarrollador de RND del artículo señaló que

En la semilla=0 la función cambia los valores iniciales al azar.

En cada reinicio, pongo semilla=0, pero la imagen con las distribuciones no cambia en los reinicios. Es decir, la afirmación es incorrecta. Tampoco se puede ver en el código por qué debería ser aleatorio. Por lo tanto, para inicializar al azar, la semilla debe establecerse en un número aleatorio, por ejemplo, seed=GetTickCount();

Para la función RandomInteger(), vemos la redistribución de los puntos en los reinicios. Si se establece srand(0);, la distribución también comienza a repetirse en los reinicios. Así que para que esta función se inicialice aleatoriamente, necesito o bien no llamar a srand, o utilizar MathSrand(GetTickCount()) con timestamp también.

Archivos adjuntos:
 

Tenga en cuenta que xor128 pasa pruebas especiales de aleatoriedad, y con rand estándar puede ser

Foro sobre comercio, sistemas de comercio automatizados y pruebas de estrategias

Aprendizaje automático en el comercio: teoría, práctica, comercio y más allá

Rorschach, 2020.04.19 22:18

Soy un manitas, he roto el 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 forma: w debe ser una potencia de 2, k es un múltiplo de 4

Forma 2: descomentar srand

El método 2 también debería funcionar con el vórtice Mersen

 
Rorschach:

Tenga en cuenta que xor128 pasa pruebas especiales de aleatoriedad, y con un rand estándar puede ser



Se muestra cada 16ª llamada de rand. Aparece algún tipo de patrón de esta periodicidad.
Estoy usando todas las llamadas consecutivas de 2 en cada una. Visualmente, por mis fotos, no veo ninguna diferencia con xor128 para 10 millones de repeticiones.
 
Rorschach:

Tenga en cuenta que xor128 pasa pruebas especiales de aleatoriedad, y con un rand estándar puede ser


Traté de sustituir mi propia función y xor128 en su función

#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() también tiene algunas divisiones.
Mejor con xor128, pero hay algo de banding:

No estoy seguro de que en el uso normal (no 1 de 16) estos guiones de RandomInteger() tengan algún efecto... Y no está claro lo que quieren decir...

Pero creo que xor128 es más seguro de usar.

 
Rorschach:

Tenga en cuenta que xor128 pasa pruebas especiales de aleatoriedad, y con un rand estándar puede ser


¿Tienes el código de Mersen? Lo tenía en OpenCL en alguna parte pero no he llegado a portarlo a MQL5. Sería interesante comparar.

El método 2 también debería funcionar con el vórtice de Mersen


 
Rashid Umarov:

¿Tienes el código de Mersen? Lo tenía en OpenCL en alguna parte pero no he llegado a portarlo a MQL5. Sería interesante comparar.

Aquí no lo he utilizado.

 
elibrarius:

Se visualiza cada 16ª llamada rand. Aparece algún tipo de patrón de esta periodicidad.
Estoy usando todas las llamadas consecutivas de 2 en cada una. Visualmente, por mis fotos, no veo ninguna diferencia con xor128 para 10 millones de repeticiones.

No sé cuál es su propósito de uso, sólo un aviso de que puede haber sorpresas.

 
Rorschach:

Aquí no lo he utilizado.

Gracias! El código resultó ser más grande que en OpenCL. Intentaré averiguarlo algún día.

 

un golpe amistoso en ter.ver, la magia de los enteros, el redondeo, la aritmética modular y los trucos del doble :-)

si f(x) :: entero uniformemente distribuido en (0;N], no significa que g(x)=N/(doble)f(x) estará uniformemente distribuido en (0;1] y también pasará todas las pruebas.

Más o menos lo mismo sobre g(x) = f(x) mod M , con la rara excepción de que N mod M = 0.

PS/ por cierto y g(x)=f(x)/(doble)N tampoco será uniforme. Habrá focos de división. Es decir, las parcelas mostrarán moiré.

PPS/ para una "prueba" visual de aleatoriedad, además del cuadrado romo del módulo, se aplican variaciones del "caracol de Ulam

 
Rorschach:

Aquí no lo he utilizado.

Medir el rendimiento de CRandomMersenne y CRandomMother a partir de este código. Son 3 veces más lentos que xor128. Esto no es muy satisfactorio. Pero según tu código, donde rompiste el GSF, se ven mejor que xor128 (sin la barra vertical).