Como é que MathRand() gera valores? - página 3

 

Adicionei oMathRandomUniform ao meu guião para comparação.
Fixei a geração de pontos em 1000000. Para estimar a distribuição, exibo todos os 1000000 pontos no ecrã como um quadrado de 1000*1000. Quanto mais vezes se atinge um ponto, mais brilhante é a sua cor.

Fixei 10 milhões de repetições de RNG, por isso, em média, cada ponto deve ser atingido 10 vezes.

Aqui estão os resultados:
RND:


A minha variante de RandomInteger:


Em MathRand():


Em MathRandomUniform():


Os dois primeiros RNDs são bastante pares, 3 e 4 têm lacunas, ou seja, nem sequer são.
Os saltos são devidos à resolução MathRand = 32767. Com um multiplicador de 1000000 obteremos saltos de 1000000/32767=30 pontos. O MathRandomUniform é semelhante por imagem, provavelmente, tem os mesmos 30 saltos.

Outra variante. Vamos definir o número máximo 30000.
RND e RandomInteger são iguais, como se fossem um milhão .MathRand e MathRandomUniform tem este aspecto (com um pedaço aumentado):


Não há lacunas (pontos negros até à posição 30000). Mas alguns são visivelmente mais brilhantes. Este é um arredondamento desigual de 30000/32767. Cada 11º ponto recebe o dobro dos acertos.

Algo uniforme pode ser obtido em MathRand a um máximo de 3000... 4000. Eis uma variante alargada para 3500:


As duas primeiras variantes ao aproximarem-se do número máximo de 100 milhões para oRandomInteger (que tem resolução decerca de 1 bilião) e 400 milhões com resolução de 4 biliões para o RND, - também começarão a ser distribuídas de forma desigual devido aos arredondamentos.

Anexei o ficheiro, pode repetir a experiência.
Decidi usar a minha própria função para mim próprio, é 25% mais lento que o RND mas mais compacto e claro, posso aumentar a resolução até 32767 vezes mais, ver código no blogue.


Nota:
O criador do RND do artigo salientou que

Na semente=0 a função muda os valores iniciais de forma aleatória.

Em cada recomeço, eu ponho semente=0, mas o quadro com as distribuições não muda no recomeço. Isto é, a declaração é incorrecta. Também não se pode ver pelo código porque é que se deve tornar aleatório. Assim, para inicializar aleatoriamente, a semente deve ser definida para um número aleatório, por exemplo seed=GetTickCount();

Para a função RandomInteger(), vemos uma redistribuição de pontos nos reinícios. Se srand(0); for definido, a distribuição também começa a repetir-se nos reinícios. Assim, para que esta função se inicialize aleatoriamente, preciso ou não chamar o srand, ou usar MathSrand(GetTickCount()) com timestamp também.

Arquivos anexados:
 

Tenha em mente que xor128 passa em testes especiais de aleatoriedade, e com rand padrão pode ser

Fórum sobre comércio, sistemas automatizados de comércio e testes estratégicos

Aprendizagem mecânica no comércio: Teoria, prática, comércio e mais além

Rorschach, 2020.04.19 22:18

Eu sou um faz-tudo, quebrei o 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 caminho: w deve ser um poder de 2, k é um múltiplo de 4

Caminho 2: descomentário

O método 2 também deve funcionar no vórtice de Mersen

 
Rorschach:

Note que xor128 passa nos testes especiais de aleatoriedade, e com um rand padrão pode ser



Exibe cada 16ª chamada rand. Surge algum tipo de padrão desta periodicidade.
Estou a utilizar todas as chamadas consecutivas de 2 em cada. Visualmente, pelas minhas fotografias, não vejo qualquer diferença com xou128 para 10 milhões de repetições.
 
Rorschach:

Note que xor128 passa em testes especiais de aleatoriedade, e com um rand padrão pode ser


Tentei substituir a minha própria função e xou128 na vossa função

#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() também tem algumas divisões.
Melhor com xor128, mas há algumas bandas:

Não tenho a certeza que em uso normal (não 1 de 16) estes traços de RandomInteger() terão qualquer efeito... E não é claro o que significam...

Mas eu penso que xor128 é mais seguro de usar.

 
Rorschach:

Note que xor128 passa em testes especiais de aleatoriedade, e com um rand padrão pode ser


Tem o código de Mersen? Tinha-o no OpenCL algures, mas não tive tempo de o portar para a MQL5. Seria interessante comparar.

O método 2 também deve funcionar no vórtice de Mersen


 
Rashid Umarov:

Tem o código de Mersen? Tinha-o no OpenCL algures, mas não tive tempo de o portar para a MQL5. Seria interessante comparar.

Aqui, eu próprio não o usei.

 
elibrarius:

Exibe cada 16º rand de chamada. Surge algum tipo de padrão desta periodicidade.
Estou a utilizar todas as chamadas consecutivas de 2 em cada. Visualmente, pelas minhas fotografias, não vejo qualquer diferença com xou128 para 10 milhões de repetições.

Não sei qual é a sua finalidade de utilização, apenas um aviso de que pode haver surpresas.

 
Rorschach:

Aqui, eu próprio não o usei.

Obrigado! O código acabou por ser maior do que no OpenCL. Tentarei descobrir um dia destes.

 

um golpe amigável em ter.ver, a magia dos inteiros, arredondamento, aritmética modular e os truques do duplo :-)

se f(x) :: número inteiro uniformemente distribuído em (0;N], não significa que g(x)=N/(duplo)f(x) será uniformemente distribuído em (0;1] e também passará em todos os testes.

Mais ou menos o mesmo sobre g(x) = f(x) mod M , com rara excepção N mod M = 0.

A propósito, PS/ e g(x)=f(x)/(duplo)N também não serão uniformes. Haverá pontos focais de divisão. Ou seja, as parcelas mostrarão moiré.

PPS/ para um "teste" visual de aleatoriedade, além do quadrado rombo do modulo, são aplicadas variações do "caracol do Ulam".

 
Rorschach:

Aqui, eu próprio não o usei.

Mediu o desempenho do CRandomMersenne e do CRandomMother a partir deste código. São 3 vezes mais lentas do que xou128. Isto não é muito satisfatório. Mas de acordo com o seu código, onde partiu o GSF, têm melhor aspecto do que xou128 (sem a barra vertical).

Razão: