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

 

Aklıma şu geldi:

 int log2_( ulong n)
{
   if (n== 0 ) return - 1 ;

   #define M(n, i, base, S) ( n >= ( ulong ( 1 )<<(i)) ? S(n, i+base/ 2 ) : S(n, i-(base+ 1 )/ 2 ) )

   #define S_0(n, i)  i
   #define S_1(n, i)  M(n, i, 1 , S_0)
   #define S_2(n, i)  M(n, i, 2 , S_1)
   #define S_4(n, i)  M(n, i, 4 , S_2)
   #define S_8(n, i)  M(n, i, 8 , S_4)
   #define S_16(n, i) M(n, i, 16 , S_8)
   #define S(n)       M(n, 32 , 32 , S_16)

   return S(n); 
}

Teoride, bu mümkün olan en hızlı olanıdır. Tüm hesaplamalar sabitlerle yapılır, bu nedenle derleme sırasında hesaplanırlar. Toplamda, hepsi sadece 6 ardışık karşılaştırmaya gelir ve daha fazlası değil. Ancak bu seçenek benim için öncekinden daha yavaş çalışıyor. sebebi nedir anlayamıyorum.

 
Alexey Navoykov :

Aklıma şu geldi:

Teoride, bu mümkün olan en hızlı olanıdır. Tüm hesaplamalar sabitlerle yapılır, bu nedenle derleme sırasında hesaplanırlar. Toplamda, hepsi sadece 6 ardışık karşılaştırmaya gelir ve daha fazlası değil. Ancak bu seçenek benim için öncekinden daha yavaş çalışıyor. sebebi nedir anlayamıyorum.

İkiye bölmek sizi yavaşlatır mı? Shift ile değiştirmeyi dener misiniz? Hesaplanan sabitlerin - hemen hesaplanması gerektiği şüphesi (bu durumda - ve tanımdaki kayma - ayrıca bir sabitle değiştirilmelidir).

Ek olarak - "soru" - bildiğim gibi, bu oldukça tartışmalı bir operatör, bir yirmi yıl önce C ++ ile kontrol ettiler, bazen "soru" normal bir if ifadesinden daha uzun kod üretir. Belki burada da aynıdır?

Ve dönüş kodunu uint yapardım - imzalı ve imzasız değerleri dönüştürürken bazı kontroller yapılırsa ne olur?

Kendi başınıza deney yapmanın bir yolu olmasa da - işlemci gözbebeklerine yüklenir ... Hatta metin "fişlerle" yazılır ...

 
Georgiy Merts :

İkiye bölmek sizi yavaşlatır mı? shift ile değiştirmeyi dener misin? Hesaplanan sabitlerin - hemen hesaplanması gerektiği şüphesi (bu durumda - ve tanımdaki kayma - ayrıca bir sabitle değiştirilmelidir).

Ayrıca - "soru sorusu" - bildiğim gibi, bu oldukça tartışmalı bir operatör ...

Bir bölümü bir vardiya ile değiştirmenin bir etkisi yoktur. Ortaya çıkan ifadenin çok uzun olduğundan şüpheleniyorum, bu nedenle derleyici onu sonuna kadar optimize etmedi.

Ancak testleri Optimize=0 ile yaptım. Optimizasyon etkinleştirildiğinde her şey yerine oturdu: ikinci seçenek yaklaşık bir buçuk kat daha hızlı. Bingo!

Optimizasyon devre dışı bırakılırsa, ikinci seçenek küçük değerler için biraz daha yavaş, ancak büyük değerler için biraz daha hızlıdır. Kısacası, ikinci seçenek kesinlikle daha iyi.

 
Alexey Navoykov :

Aklıma şu geldi:

Teoride, bu mümkün olan en hızlı olanıdır. Tüm hesaplamalar sabitlerle yapılır, bu nedenle derleme sırasında hesaplanır. Toplamda, hepsi sadece 6 ardışık karşılaştırmaya gelir ve daha fazlası değil. Ancak bu seçenek benim için öncekinden daha yavaş çalışıyor. sebebi nedir anlayamıyorum.

Bu doğru - seçeneğiniz en hızlısı.

Sadece boş bir test. Çok sık olarak, performans testi yapılırken önemli bir nokta unutulur: hesaplanan değer hiçbir yerde kullanılmazsa, derleyici basitçe hesaplamayı yapmaz.

Sonuçta, bu mantıklı - ne anlamı var? Kuantum süperpozisyonu gibi. Kimse bakmıyorsa ay neden var olsun ki? "Ay sadece bir fare ona baktığı için mi var oluyor?" (Albert Einstein). :))

Bu nedenle, sağlama toplamının hesaplanması ve yazdırılmasıyla testin bu sürümü daha doğru olacaktır:

 #property strict
#define   test(M,S,EX)        { long sum= 0 ; uint nn=( uint ) pow ( 10 ,M); ulong mss= GetMicrosecondCount (); for ( uint t12= 1 ;t12<=nn;t12++){EX;sum+=( long )n1;} \
                                 Print (S+ ": loops=" +( string )nn+ " μs=" + string ( GetMicrosecondCount ()-mss)+ " Контрольная сумма=" + string (sum));}

int log2( ulong n){
   if (n== 0 ) return - 1 ;
   #define S(k) if (n >= ( ulong ( 1 )<<k)) { i += k;  n >>= k; }
   int i= 0 ;  S( 32 );  S( 16 );  S( 8 );  S( 4 );  S( 2 );  S( 1 );   return i;
   #undef S}


static const uint ulLogTable[ 64 ] = {
0 , 58 , 1 , 59 , 47 , 53 , 2 , 60 , 39 , 48 , 27 , 54 , 33 , 42 , 3 , 61 ,
51 , 37 , 40 , 49 , 18 , 28 , 20 , 55 , 30 , 34 , 11 , 43 , 14 , 22 , 4 , 62 ,
57 , 46 , 52 , 38 , 26 , 32 , 41 , 50 , 36 , 17 , 19 , 29 , 10 , 13 , 21 , 56 ,
45 , 25 , 31 , 35 , 16 , 9 , 12 , 44 , 24 , 15 , 8 , 23 , 7 , 6 , 5 , 63 };

uint _FastLog2( ulong ulInput){
   ulInput |= ulInput >> 1 ;
   ulInput |= ulInput >> 2 ;
   ulInput |= ulInput >> 4 ;
   ulInput |= ulInput >> 8 ;
   ulInput |= ulInput >> 16 ;
   ulInput |= ulInput >> 32 ;  
   return (ulLogTable[( uint )((ulInput * 0x03f6eaf2cd271461 ) >> 58 )]);};
   
int log2_( ulong n)
{
   if (n== 0 ) return - 1 ;

   #define M(n, i, base, S) ( n >= ( ulong ( 1 )<<(i)) ? S(n, i+base/ 2 ) : S(n, i-(base+ 1 )/ 2 ) )

   #define S_0(n, i)  i
   #define S_1(n, i)  M(n, i, 1 , S_0)
   #define S_2(n, i)  M(n, i, 2 , S_1)
   #define S_4(n, i)  M(n, i, 4 , S_2)
   #define S_8(n, i)  M(n, i, 8 , S_4)
   #define S_16(n, i) M(n, i, 16 , S_8)
   #define S(n)       M(n, 32 , 32 , S_16)

   return S(n); 
}

void OnStart (){
   srand ( GetTickCount ());
   ulong n1;
  test( 8 , "MathLog" ,n1= ulong ( MathLog (( double )t12)/ MathLog ( 2.0 )))
  test( 8 , "log2" ,n1=log2(t12))
  test( 8 , "log2_" ,n1=log2_(t12))
  test( 8 , "_FastLog2" ,n1=_FastLog2(t12))}

Sonuç:

 2019.01 . 05 02 : 30 : 03.681 TestLog (.BrentCrud,H4) MathLog :   loops= 100000000 μs= 805196 Контрольная сумма= 2465782300
2019.01 . 05 02 : 30 : 04.092 TestLog (.BrentCrud,H4) log2:      loops= 100000000 μs= 410657 Контрольная сумма= 2465782300
2019.01 . 05 02 : 30 : 04.234 TestLog (.BrentCrud,H4) log2_:     loops= 100000000 μs= 141975 Контрольная сумма= 2465782300
2019.01 . 05 02 : 30 : 04.432 TestLog (.BrentCrud,H4) _FastLog2: loops= 100000000 μs= 198015 Контрольная сумма= 2465782300
Ve ikinci sırada hala _FastLog2, log2 değil :))
 
Nikolai Semko :

Sadece boş bir test. Çok sık olarak, performans testi yapılırken önemli bir nokta unutulur: hesaplanan değer hiçbir yerde kullanılmazsa, derleyici basitçe hesaplamayı yapmaz.

Sonuçta, bu mantıklı - ne anlamı var? Kuantum süperpozisyonu gibi. Kimse bakmıyorsa ay neden var olsun ki? "Ay sadece bir fare ona baktığı için mi var oluyor?" (Albert Einstein). :))

Bu nedenle, sağlama toplamının hesaplanması ve yazdırılmasıyla testin bu sürümü daha doğru olacaktır:

Kodunuz kafa karıştırıcı. Tanımlamada kullanılan değişkenler program kodunun diğer ucunda bulunur - bu tür kaosu anlamak elverişsizdir. Ancak mesele bu değil, testlerinizin sonuçlarının güvenilir kabul edilemeyeceği gerçeğidir, çünkü. derleyici, fonksiyona iletilen değerlerin algoritmasını önceden bilir. Bu nedenle testlerinizi optimize eder. Rastgele sayılara güvenmeniz gerekir.

Bu arada, neden kodunuzda srand var? İlk gördüğümde rastgele kullandığınızı düşündüm, ama aslında - hayır.

İşte kodum:

 void OnStart ()
{
   Print ( "OnStart" );
   srand ( GetTickCount ());
   int count= 50000000 ;
   
   #define TEST(func) { \ 
     ulong sum= 0 ; \
     ulong mcscount= GetMicrosecondCount (); \
     for ( int i= 0 ; i<count; i++) \
      sum += func( rand () | rand ()<< 15 ); \
     Print ( "Result " + #func + ":  sum=" ,sum, "  time=" ,( GetMicrosecondCount ()-mcscount)/ 1000 , " ms" ); \    
  }
  
  TEST(log2);
  TEST(log2_);
}
 
Alexey Navoykov :

Kodunuz kafa karıştırıcı. Tanımlamada kullanılan değişkenler program kodunun diğer ucunda bulunur - bu tür kaosu anlamak elverişsizdir. Ancak mesele bu değil, testlerinizin sonuçlarının güvenilir kabul edilemeyeceği gerçeğidir, çünkü. derleyici, fonksiyona iletilen değerlerin algoritmasını önceden bilir. Bu nedenle testlerinizi optimize eder. Rastgele sayılara güvenmeniz gerekir.

Bu arada, neden kodunuzda srand var? İlk gördüğümde rastgele kullandığınızı düşündüm, ama aslında - hayır.

İşte kodum:

kod benim değil Az önce düzelttim ve sağlama toplamlarının kimliğini kontrol etmek ve nispeten pahalı Rand işlevlerini döngüden çıkarmak için Rand'ı attım ve srand onu atmayı unuttu.

rand'ı iade ediyorum. Haklısın - derleyici ardışık değerlerden logaritma toplamının döngüsünü optimize ediyor. Şaşırmış olmama rağmen. Bunu nasıl yaptığını anlamıyorum. Belki de hesaba katmadığımız bir şey vardır.

 #property strict
#define   test(M,S,EX)        { srand ( 45 ); long sum= 0 ; uint nn=( uint ) pow ( 10 ,M); ulong mss= GetMicrosecondCount (); for ( uint t12= 1 ;t12<=nn;t12++){EX;sum+=( long )n1;} \
                                 Print (S+ ": loops=" +( string )nn+ " μs=" + string ( GetMicrosecondCount ()-mss)+ " Контрольная сумма=" + string (sum));}

int log2( ulong n){
   if (n== 0 ) return - 1 ;
   #define S(k) if (n >= ( ulong ( 1 )<<k)) { i += k;  n >>= k; }
   int i= 0 ;  S( 32 );  S( 16 );  S( 8 );  S( 4 );  S( 2 );  S( 1 );   return i;
   #undef S}


static const uint ulLogTable[ 64 ] = {
0 , 58 , 1 , 59 , 47 , 53 , 2 , 60 , 39 , 48 , 27 , 54 , 33 , 42 , 3 , 61 ,
51 , 37 , 40 , 49 , 18 , 28 , 20 , 55 , 30 , 34 , 11 , 43 , 14 , 22 , 4 , 62 ,
57 , 46 , 52 , 38 , 26 , 32 , 41 , 50 , 36 , 17 , 19 , 29 , 10 , 13 , 21 , 56 ,
45 , 25 , 31 , 35 , 16 , 9 , 12 , 44 , 24 , 15 , 8 , 23 , 7 , 6 , 5 , 63 };

uint _FastLog2( ulong ulInput){
   ulInput |= ulInput >> 1 ;
   ulInput |= ulInput >> 2 ;
   ulInput |= ulInput >> 4 ;
   ulInput |= ulInput >> 8 ;
   ulInput |= ulInput >> 16 ;
   ulInput |= ulInput >> 32 ;  
   return (ulLogTable[( uint )((ulInput * 0x03f6eaf2cd271461 ) >> 58 )]);};
   
int log2_( ulong n)
{
   if (n== 0 ) return - 1 ;

   #define M(n, i, base, S) ( n >= ( ulong ( 1 )<<(i)) ? S(n, i+base/ 2 ) : S(n, i-(base+ 1 )/ 2 ) )

   #define S_0(n, i)  i
   #define S_1(n, i)  M(n, i, 1 , S_0)
   #define S_2(n, i)  M(n, i, 2 , S_1)
   #define S_4(n, i)  M(n, i, 4 , S_2)
   #define S_8(n, i)  M(n, i, 8 , S_4)
   #define S_16(n, i) M(n, i, 16 , S_8)
   #define S(n)       M(n, 32 , 32 , S_16)

   return S(n); 
}

void OnStart (){
   ulong n1,n;
  test( 8 , "MathLog" ,n=( rand ()+ 1 )*( rand ()+ 1 );n1= ulong ( MathLog (( double )n)/ MathLog ( 2.0 )))
  test( 8 , "log2" ,n=( rand ()+ 1 )*( rand ()+ 1 );n1=log2(n))
  test( 8 , "log2_" ,n=( rand ()+ 1 )*( rand ()+ 1 );n1=log2_(n))
  test( 8 , "_FastLog2" ,n=( rand ()+ 1 )*( rand ()+ 1 );n1=_FastLog2(n))}

Sonuç:

 2019.01 . 05 04 : 10 : 25.808 TestLog (EURUSD,H1)     MathLog :   loops= 100000000 μs= 1168737 Контрольная сумма= 2661391201
2019.01 . 05 04 : 10 : 26.474 TestLog (EURUSD,H1)     log2:      loops= 100000000 μs= 665631   Контрольная сумма= 2661391201
2019.01 . 05 04 : 10 : 27.315 TestLog (EURUSD,H1)     log2_:     loops= 100000000 μs= 841299   Контрольная сумма= 2661391201
2019.01 . 05 04 : 10 : 27.694 TestLog (EURUSD,H1)     _FastLog2 :  loops= 100000000 μs= 378627    Контрольная сумма= 2661391201
   

Mevcut kazanan _FastLog2

 
Nikolai Semko :

Sonuç:

Mevcut kazanan _FastLog2

Değerler rastgele ise, her yerde aynı sağlama toplamını nasıl elde ettiğinizi merak ediyorum.

 
Alexey Navoykov :

Değerler rastgele ise, her yerde aynı sağlama toplamını nasıl elde ettiğinizi merak ediyorum.

tüm işlevler için srand(45)

Ben de ilk başta yaptım ama farklı sağlama toplamları aldım, tk. rand()*rand() öğesinin 0 olabileceğini hesaba katmadı ve bu sağlama toplamını bozar. Şimdi sıfırdan uzaklaşmak için bir eklendi.

 
Nikolai Semko :

tüm işlevler için srand(45)

Ben de ilk başta yaptım ama farklı sağlama toplamları aldım, tk. rand()*rand() öğesinin 0 olabileceğini hesaba katmadı ve bu sağlama toplamını bozar. Şimdi sıfırdan uzaklaşmak için bir eklendi.

Ve özellikle hızı ölçmekten bahsediyorsak, neden aynı sağlama toplamına ihtiyacınız var? Bu durumda toplamın özü, derleyicinin kodu kesmesini engellemektir, hepsi bu. Ve srand(45) yaparak, testin tekrar optimize edilmesine izin vermiş olursunuz.

Bu arada, yaklaşık sıfır. FastLog2'de sıfır kontrolü yoktur, bu da buna göre avantajlı bir başlangıç sağlar. Ancak, doğru bir şekilde test edilirse, yine de log2'den bir buçuk ila iki kat daha yavaştır)

 
Alexey Navoykov :
Ve özellikle hızı ölçmekten bahsediyorsak, neden aynı sağlama toplamına ihtiyacınız var? Bu durumda toplamın özü, derleyicinin kodu kesmesini engellemektir, hepsi bu. Ve srand(45) yaparak, testin tekrar optimize edilmesine izin vermiş olursunuz.

Burada derleyicinin yeteneklerini abartıyorsunuz. Kaldır srand(45) - sağlama toplamları farklı olacaktır, ancak hız sonucu korunacaktır.

Ayrıca, deneyin saflığı için hesaplamaların aynı olduğu gerçeği beni yönlendirdi, çünkü tüm işlevlerin ayrıntılarına girmedi. Bazen bir işlev parametresinin değeri, yürütme süresini etkileyebilir.

Özellikle aynı zamanda algoritmaların doğruluğunu kontrol etmek için.