Mql5 dilinin özellikleri, incelikleri ve çalışma yöntemleri - sayfa 136

 
Nikolai Semko :
Onlar. Yatağın altına yuvarlanan 10 senti bulmak için 100 dolarlık banknotu ateşe vermeye hazır mısınız?

Bir madeni para olabilir veya olmayabilir.

   srand ( GetTickCount ());
   uint v10 = 0 , v19900 = 0 ;
   for ( uint i = 0 ;  i < UINT_MAX ;  ++ i) {
       int cur = rand ();
       if (cur % 20000   == 10 )
         ++ v10;
       else if (cur % 20000   == 19900 )
         ++ v19900;   
   }
   Alert ( "10 probability = " , ( double )v10/ UINT_MAX * 100 , "%;  1990 probability = " , ( double )v19900/ UINT_MAX * 100 , "%" );
   // Alert: 10 probability = 0.006103515626421085%;  19900 probability = 0.003051757813210543%
        

Onlarca ihtimal iki katıdır. Ve en önemlisi, get_rand()'ın maliyeti hakkındaki iddialar havada uçuştu, öyleyse neden normal olarak yapabiliyorken (tekdüze bir dağılım beklerken) değişen bir olasılıkla anüsten rasgele sayılar alıyorsunuz? 100 dolarlık bir banknotu biriktirmiyorsunuz, ancak eşleşiyor.

 
Vict :

Bir madeni para olabilir veya olmayabilir.

Onlarca ihtimal iki katıdır. Ve en önemlisi, get_rand()'ın maliyeti hakkındaki iddialar havada uçuştu, öyleyse neden normal olarak yapabiliyorken (tekdüze bir dağılım beklerken) değişen bir olasılıkla anüsten rasgele sayılar alıyorsunuz? 100 dolarlık bir banknotu biriktirmiyorsunuz, ancak eşleşiyor.

Evet, işlevinizin güçlü yavaşlığı konusunda yanılmışım. Algoritmayı yanlış anladım. Soryan.
Ama yine de, algoritmam, sizinki gibi daha evrensel ve 32767 sayısı ile sınırlı olmamasına rağmen, önerilenlerin en hızlısı olduğu ortaya çıktı.
Kanıt kodu.

Bu komut dosyası, rastgele bir renk ve rastgele koordinatlara sahip bir dizi noktayı rastgele oluşturur. Dizi boyutu, grafik grafiğindeki piksel sayısına eşittir. Bu 5 kez tekrarlanır

  1. standart Rand() işlevini kullanarak
  2. get_rand() işlevinizi kullanarak
  3. ulong randUlong() işlevimle
  4. uint randUint() işlevimle
  5. @Alexey Navoykov'dan ulong RandomLong() işlevini kullanarak
 2019.06 . 09 03 : 42 : 25.958 TestSpeedRand (EURGBP,H4)       Время формирования случайных массивов = 9894 микросекунд.  Всего сгенерировано 5203975 случайных чисел rand ()
2019.06 . 09 03 : 42 : 28.010 TestSpeedRand (EURGBP,H4)       Время формирования случайных массивов = 24899 микросекунд. Всего сгенерировано 5203975 случайных чисел get_rand()
2019.06 . 09 03 : 42 : 30.057 TestSpeedRand (EURGBP,H4)       Время формирования случайных массивов = 22172 микросекунд. Всего сгенерировано 5203975 случайных чисел randUlong()
2019.06 . 09 03 : 42 : 32.098 TestSpeedRand (EURGBP,H4)       Время формирования случайных массивов = 16013 микросекунд. Всего сгенерировано 5203975 случайных чисел randUint()
2019.06 . 09 03 : 42 : 34.145 TestSpeedRand (EURGBP,H4)       Время формирования случайных массивов = 25524 микросекунд. Всего сгенерировано 5203975 случайных чисел RandomLong()

Rakamlar, rand()% 20000 kullandığımızda sorunun özünü gösterecek şekilde seçilmiştir.


olmalı:


 //+------------------------------------------------------------------+
uint get_rand( uint max)
  {
   static bool f= false ;
   if (!f) 
     {
      f= true ;
       srand ( GetTickCount ());
     }
   uint limit=(max+ 1 ) *(( 32767 + 1 )/(max+ 1 ));
   uint val;
   while ((val= rand ())>=limit);
   return val % (max+ 1 );
  }
//+------------------------------------------------------------------+
ulong randUlong( ulong max= ULONG_MAX ){ return ((( ulong ) rand ()<< 60 )|(( ulong ) rand ()<< 45 )|(( ulong ) rand ()<< 30 )|(( ulong ) rand ()<< 15 )|( ulong ) rand ())%max;}
//+------------------------------------------------------------------+
uint randUint( uint max= UINT_MAX ) { return ((( uint ) rand ()<< 30 )|(( uint ) rand ()<< 15 )|( uint ) rand ())%max;}
//+------------------------------------------------------------------+
ulong RandomLong( ulong range)
  {
#define _MAXRND(rang,rnd_range) ((rnd_range) -((rnd_range)-rang)%rang- 1 )
#define _RND ulong ( rand ())
   ulong rnd,max, const bit= 1 ;
   if (range <= bit<< 15 ) { if (!range) return 0 ;  max=_MAXRND(range, 1 << 15 );   while ((rnd=_RND) > max);   return rnd%range; }
   if (range <= bit<< 30 ) { max=_MAXRND(range, bit<< 30 );   while ((rnd=(_RND | _RND<< 15 )) > max);   return rnd%range; }
   if (range <= bit<< 45 ) { max=_MAXRND(range, bit<< 45 );   while ((rnd=(_RND | _RND<< 15 | _RND<< 30 )) > max);   return rnd%range;  }
   if (range <= bit<< 60 ) { max=_MAXRND(range, bit<< 60 );   while ((rnd=(_RND | _RND<< 15 | _RND<< 30 | _RND<< 45 )) > max);   return rnd%range; }
   else   { max=_MAXRND(range,bit<< 64 );   while ((rnd=(_RND|_RND<< 15 |_RND<< 30 |_RND<< 45 |_RND<< 60 ))>max);   return rnd%range; }
#undef _RND
#undef _MAXRND
  }
//+------------------------------------------------------------------+
Tehdit, ancak vakaların %99,9'unda bu işlev de çalışacaktır:
 uint randUint( uint max) { return ((( uint ) rand ()<< 15 )|( uint ) rand ())%max;}
daha da hızlı çalışacaktır.
bu fonksiyon 0 ile 1073741824 arasında rastgele bir sayı üretecektir. bu sayı tüm geçmişteki herhangi bir enstrüman için tik sayısından bile daha fazladır. Böyle bir işlevin "sahtekarlığı", görevlerin %99,9'u için mikroskobik olacaktır.
Dosyalar:
 
Nikolai Semko :

Ama yine de, algoritmam, sizinki gibi daha evrensel olmasına ve 32767 sayısıyla sınırlı olmamasına rağmen, önerilenlerin en hızlısı olduğu ortaya çıktı.
Kanıt kodu.

Sıkı çalışma için teşekkürler, gerçekten ilginç sonuçlar. Rand() işlevinin o kadar hızlı olduğu ortaya çıktı ki, aritmetik işlemlerden daha hızlı çalışıyor.

 
Alexey Navoykov :

Sıkı çalışma için teşekkürler, gerçekten ilginç sonuçlar. Rand() işlevinin o kadar hızlı olduğu ortaya çıktı ki, aritmetik işlemlerden daha hızlı çalışıyor.

hayır, daha hızlı değil. Yaklaşık bir nanosaniye, tıpkı bir çiftin karekökünü almak gibi. +-*/ işlemler bir nanosaniyenin kesirlerinde gerçekleştirilir.
Ancak karekök gibi, Rand() modern işlemcilerde yazılımda değil, donanım düzeyinde yapılır.

 
Nikolai Semko :

hayır, daha hızlı değil. Yaklaşık bir nanosaniye, tıpkı bir çiftin karekökünü almak gibi. +-*/ işlemler bir nanosaniyenin kesirlerinde gerçekleştirilir.
Ancak karekök gibi, Rand() modern işlemcilerde yazılımda değil, donanım düzeyinde yapılır.

Evet ise neden olmasın. Sürümünüz benimkinden farklıdır, çünkü her zaman 5 Rand() ve benimki: 20000 aralığında ortalama 1.64 kez ve 256 aralığında 1 kez. Toplamda, Rand() her yineleme için 25 kez çağrılır. , ve bende 1,64*2+3 = 5,3 kez var. Genel olarak, elbette, garip bir durum, sebebinin tam olarak ne olduğunu bulmak gerekiyor. Ayrıca orada ek olarak bir sürü bit işleminiz var ...

 
Nikolai Semko :

1. Peki, fonksiyonlarınızda sorunun çözülmediğini, sadece gizlendiğini anlıyoruz, kilo vermeyeceğim, ancak kemeri daha sıkı sıkın.

2. Alexey ile olan seçeneklerimizde bu en kötü seçenektir, diğer birçok durumda hız neredeyse rand() düzeyinde olacaktır, ancak sabit zamanınız var.

3. Rand()'ın neden bu kadar dar bir aralıkta sayılar ürettiğini hiç merak ettiniz mi? Bu sözde rasgele bir üreteçtir, yani periyodiktir, bu nedenle gerekmediği yerde bir grup rasgele sayı üretir ve sonra onları atar, kalitesi kötüleşir (tekrarlar daha erken olur).

4. Bazıları rastgele verileri daha karmaşık bir şekilde alır. Mesela ben ağdan çektim, birileri bile satın alabilir. Bu yüzden, daha sonra aptalca atmak için zorlukla elde edilen verileri boşa harcamam gerekiyor (ulong oluşturmak, doğru algoritmayı yazmak - bu bizim yolumuz değil)?

 
Alexey Navoykov :

Evet ise neden olmasın. Sürümünüz benimkinden farklıdır, çünkü her zaman 5 Rand() ve benimki: 20000 aralığında ortalama 1.64 kez ve 256 aralığında 1 kez. Toplamda, Rand() her yineleme için 25 kez çağrılır. , ve bende 1,64*2+3 = 5,3 kez var. Genel olarak, elbette, garip bir durum, sebebinin tam olarak ne olduğunu bulmak gerekiyor. Çünkü ek olarak gerçekleştirilen bir sürü bit işleminiz de var ...

bitsel en ucuz işlemlerdir. Neredeyse ücretsiz.

Ama genel olarak katılıyorum. Nedenini ben de anlamıyorum ... Belki de optimizasyonun mucizeleri. Yine de ne geliştirilebilir ...

 
Nikolai Semko :

bitsel en ucuz işlemlerdir. Neredeyse ücretsiz.

Ama genel olarak katılıyorum. Nedenini ben de anlamıyorum ... Belki de optimizasyonun mucizeleri. Yine de ne geliştirilebilir ...

Aritmetik işlemlerle ilgili değil gibi görünüyor, çünkü orada değiller, derleme aşamasında tüm değerler hesaplanır. Bunun nedeni, bilinmeyen sayıda yinelemeli bir döngünün varlığıdır (bu yinelemeler ortalama olarak ikiden az olmasına rağmen). Böylece kodunuz, bilinen sayıda Rand() çağrısı ile bir şekilde optimize edilir.
 
Vict :

1. Peki, fonksiyonlarınızda sorunun çözülmediğini, sadece gizlendiğini anlıyoruz, kilo vermeyeceğim, ancak kemeri daha sıkı sıkın.

2. Alexey ile olan seçeneklerimizde bu en kötü seçenektir, diğer birçok durumda hız neredeyse rand() düzeyinde olacaktır, ancak sabit zamanınız var.

3. Rand()'ın neden bu kadar dar bir aralıkta sayılar ürettiğini hiç merak ettiniz mi? Bu sözde rasgele bir üreteçtir, yani periyodiktir, bu nedenle gerekmediği yerde bir grup rasgele sayı üretir ve sonra onları atar, kalitesi kötüleşir (tekrarlar daha erken olur).

4. Bazıları rastgele verileri daha karmaşık bir şekilde alır. Mesela ben ağdan çektim, birileri bile satın alabilir. Bu yüzden, daha sonra aptalca atmak için zorlukla elde edilen verileri boşa harcamam gerekiyor (ulong oluşturmak, doğru algoritmayı yazmak - bu bizim yolumuz değil)?

Bu zaten sıkıcı.
Bu sorunun %0,1 oranında bile fark edilebildiği bir durumu yeniden oluşturmak için aşağıdaki değerlerin üzerindeki aralıklarda çalışmanız gerekir:

  • (ULONG_MAX)/1000= randUlong() işlevi için 18446744073709551
  • (UINT_MAX)/1000= randUint() işlevi için 4294967

Hiç böyle aralıklar kullandınız mı? O zaman neden bu kontrolleri ve döngüleri koydunuz?
İyinin düşmanı en iyisi.

Şahsen benim rasgele sayı üretme aralıklarım pratikte 2000, maksimum 4000 ile sınırlı. Rand() bunun için oldukça iyi çalışıyor.
Bunu koduma yapıştırın:

 ulong t= GetMicrosecondCount ();
   for ( int i= 0 ;i<size;i++)
     {
      X[i]= ushort ( rand ()%W.Width);
      Y[i]= ushort ( rand ()%W.Width);
      clr[i]=XRGB( rand ()% 256 , rand ()% 256 , rand ()% 256 );
     }
   t= GetMicrosecondCount ()-t;
   Print ("Время формирования случайных массивов = "+ string (t)+" микросекунд. Всего сгенерировано "+ string (size* 5 )+" случайных чисел rand ()%W.Width");
   Canvas.Erase();
   for ( int i= 0 ;i<size;i++) Canvas.PixelSet(X[i],Y[i],clr[i]);
   Canvas.Update();
   Sleep ( 2000 );

ve Rand() işlevinin "sahtekarlığını" fark etmeyeceksiniz (Rand()%20000 varyantında olduğu gibi) ve noktalar görsel olarak eşit aralıklarla yerleştirilecektir, bu nedenle oldukça çalışır ve en hızlısıdır.

Tehdit İşlemci geliştiricilerinin Rand() öğesini 2 ^ 15 = 32768 değeriyle sınırlaması boşuna değildir. Onlar aptal insanlar değil. Bu, pratik görevlerin %99'unu tamamen kapsar.
Ve "çirkin" fikirleri sevenler için seçenek fazlasıyla yeterli:

 ulong randUlong( ulong max= ULONG_MAX ){ return ((( ulong ) rand ()<< 60 )|(( ulong ) rand ()<< 45 )|(( ulong ) rand ()<< 30 )|(( ulong ) rand ()<< 15 )|( ulong ) rand ())%max;}
Dosyalar:
 
Nikolai Semko :

Şahsen benim rasgele sayı üretme aralıklarım pratikte 2000, maksimum 4000 ile sınırlı. Rand() bunun için oldukça iyi çalışıyor.
Bunu koduma yapıştırın:

ve Rand() işlevinin "sahtekarlığını" fark etmeyeceksiniz (Rand()%20000 varyantında olduğu gibi) ve noktalar görsel olarak eşit aralıklarla yerleştirilecektir, bu nedenle oldukça çalışır ve en hızlısıdır.

tadını çıkar, umurumda değil. Özellikle % öğesinin sağında RAND_MAX+1'in (256 veya 1024) katı olduğunda.

Tehdit İşlemci geliştiricilerinin Rand() öğesini 2 ^ 15 = 32768 değeriyle sınırlaması boşuna değildir. Onlar aptal insanlar değil. Bu, pratik görevlerin %99'unu tamamen kapsar.
Ve "çirkin" fikirleri sevenler için seçenek fazlasıyla yeterli:

İşlemci geliştiricilerinin nesi var? Jeneratör - yazılım uygulandı. Tek gereksinim RAND_MAX >= 32767 ve en az 2^32 noktadır. Yani mikrolitrelerde "minimum" da çok yetersiz bir jeneratör var.

Ve en ileri görüşlüler kendilerini dürüst bir rand () yapacaktır (çokluk yoksa), bu referans kitaplarında bile tavsiye edilir.