ceil(), round(), floor() fonksiyonlarının yürütme hızı

 

Programcılarla beklenmedik, basit ve kullanışlı keşfimi paylaşmak istiyorum.

Yuvarlama fonksiyonları:

 floor (), ceil (), round () 
они же
MathFloor (), MathCeil (), MathRound ()

çok yavaş olduğu ortaya çıktı. Yuvarlama işlemini 4-5 kat hızlandırmak için (MQL5 testlerime göre), bu işlevleri basit bir alternatifle değiştirebilirsiniz:

 double x= 45.27 ;
int y;
//работает только для положительных чисел!!! 
y= floor (x); -> y=( int )x;
y= ceil (x);  -> y=(x-( int )x> 0 )?( int )x+ 1 :( int )x;   //более быстрым вариантом является: -> y=(int)(x+0.9999999999999997), но при этом возможна некорректная отработка
y= round (x); -> y=( int )(x+ 0.5 );

Удобнее использовать #define. Например:
#define _ceil(x) (x-( int )x> 0 )?( int )x+ 1 :( int )x
y=_ceil(x);

// Для положительных и отрицательных чисел: ( выигрыш в скорости - в 3-4 раза)
#define _ceil(x) (x-( int )x> 0 )?( int )x+ 1 :( int )x
#define _round(x) (x> 0 )?( int )(x+ 0.5 ):( int )(x- 0.5 )
#define _floor(x) (x> 0 )?( int )x:(( int )x-x> 0 )?( int )x- 1 :( int )x

Çünkü bu işlevler genellikle büyük ve iç içe döngülerde kullanılır, performans kazancı oldukça önemli olabilir.

Muhtemelen sadecebir işlevi çağırmak çok zaman alıcıdır (yığın üzerinde farklı veri, adres vb. depolamak). Ve bu durumda, işlevsiz yapabilirsiniz.

Performans testini içeren komut dosyası ektedir.

Dosyalar:
TestSpeed.mq5  3 kb
 
Nikolai Semko :

Programcılarla beklenmedik, basit ve kullanışlı keşfimi paylaşmak istiyorum.

Yuvarlama fonksiyonları:

çok yavaş olduğu ortaya çıktı. Yuvarlama işlemini 4-5 kat hızlandırmak için (MQL5 testlerime göre), bu işlevleri basit bir alternatifle değiştirebilirsiniz:

Çünkü bu işlevler genellikle büyük ve iç içe döngülerde kullanılır, performans kazancı oldukça önemli olabilir.

Muhtemelen sadecebir işlevi çağırmak çok zaman alıcıdır (yığın üzerinde farklı veri, adres vb. depolamak). Ve bu durumda, işlevsiz yapabilirsiniz.

Performans testini içeren komut dosyası ektedir.

Sadece ben bu çizgiyle

y= round (x); -> y=( int )(x+ 0.5 );

aynı fikirde olmamak. Matematik kurallarına göre kesirli kısım 0,5'ten küçükse aşağı yuvarlama yapılır. Ancak 0,5 ila 45,27 eklerseniz, daha büyük bir sayıya yuvarlanır.

 
Alexey Viktorov :

Sadece ben bu çizgiyle

aynı fikirde olmamak. Matematik kurallarına göre kesirli kısım 0,5'ten küçükse aşağı yuvarlama yapılır. Ancak 0,5 ila 45,27 eklerseniz, daha büyük bir sayıya yuvarlanır.


 #define MUL(x) ((x)+( 0.5 )) 
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart ()
  {
   ulong t0,t1,t2,t3;
   int y0[],y1[],y2[];
   ArrayResize (y0, 10000000 );
   ArrayResize (y1, 10000000 );
   ArrayResize (y2, 10000000 );
   double x= 1.45 ;  

   for ( int i= 0 ;i< 10000000 ;i++)
     {
       if (( int )(x+ 0.5 )!=( int ) round (x)) Print ( "ой..." ,x);
      x+= 0.27 ;
      y0[i]+= 0 ;
      y1[i]+= 0 ;
      y2[i]+= 0 ;
     }
     Print ( "y0[]: " ,y0[ 9999999 ], " / y1[]: " ,y1[ 9999999 ], " / y2[]: " ,y2[ 9999999 ]);
   x= 1.45 ;
   t0= GetMicrosecondCount ();
   for ( int i= 0 ;i< 10000000 ;i++)
     {
      y0[i]=( int ) MathRound (x);
      x+= 0.27 ;
     }
   t1= GetMicrosecondCount ()-t0;
   Print ( "y0[]: " ,y0[ 9999999 ]);
   x= 1.45 ;
   t0= GetMicrosecondCount ();
   for ( int i= 0 ;i< 10000000 ;i++)
     {
      y1[i]=( int )(x+ 0.5 );
      x+= 0.27 ;
     }
   t2= GetMicrosecondCount ()-t0;
   Print ( "y1[]: " ,y1[ 9999999 ]);
   x= 1.45 ;
   t0= GetMicrosecondCount ();
   for ( int i= 0 ;i< 10000000 ;i++)
     {
      y2[i]=( int )MUL(x);
      x+= 0.27 ;
     }
   t3= GetMicrosecondCount ()-t0;
   Print ( "y2[]: " ,y2[ 9999999 ]);
   Print ( "Цикл округления 10 000 000 раз: (round) = " , IntegerToString (t1), "   альтернатива с (int) = " , IntegerToString (t2), "   альтернатива с (#define) = " , IntegerToString (t3), " микросекунд" );
  }
//+------------------------------------------------------------------+
 
Alexey Viktorov :

Sadece ben bu çizgiyle

aynı fikirde olmamak. Matematik kurallarına göre kesirli kısım 0,5'ten küçükse aşağı yuvarlama yapılır. Ancak 0,5 ila 45,27 eklerseniz, daha büyük bir sayıya yuvarlanır.


ne karıştırıyorsun. Doğrulama kodunu özellikle örnek olarak ekledim:

 for ( int i= 0 ;i< 10000000 ;i++)
     {
       if (( int )(x+ 0.5 )!=( int ) round (x)) Print ( "ой..." ,x);
      x+= 0.27 ;
     }

yanılmış olsaydım, Print deyimi yürütülürdü ( "oops..." ,x);

Deneyin - her şey yolunda.

 
Alexey Viktorov :

Sadece ben bu çizgiyle

aynı fikirde olmamak. Matematik kurallarına göre kesirli kısım 0,5'ten küçükse aşağı yuvarlama yapılır. Ancak 0,5 ila 45,27 eklerseniz, daha büyük bir sayıya yuvarlanır.


Ve eğer alır ve kontrol ederseniz? ))) int(45.27 + 0.5) 46'yı nasıl verecek? Aynı 45 kalacak.

 
Lilita Bogachkova :


Hızdan bahsetmiyorum.

 
Nikolai Semko :

ne karıştırıyorsun. Doğrulama kodunu özellikle örnek olarak ekledim:

yanılmış olsaydım, Print deyimi yürütülürdü ( "oops..." ,x);

Deneyin - her şey yolunda.


Ancak dizi önceden veriyle doldurulmazsa hızın değişmesi yine de ilginçtir.


 #define _round(x) (int)((x)+( 0.5 )) 
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart ()
  {
   ulong t0,t1,t2;
   int y0[],y1[];
   ArrayResize (y0, 10000000 );

   double x= 1.45 ;  

   for ( int i= 0 ;i< 10000000 ;i++)
     {
       if (( int )(x+ 0.5 )!=( int ) round (x)) Print ( "ой..." ,x);
      x+= 0.27 ;
       y0[i]+= 0 ; // !!!!!!!!!!!!!!
     }

   x= 1.45 ;
   t0= GetMicrosecondCount ();
   for ( int i= 0 ;i< 10000000 ;i++)
     {
      y0[i]=( int )(x+ 0.5 );
      x+= 0.27 ;
     }
   t1= GetMicrosecondCount ()-t0;

   x= 1.45 ;
   t0= GetMicrosecondCount ();
   for ( int i= 0 ;i< 10000000 ;i++)
     {
      y0[i]=_round(x);
      x+= 0.27 ;
     }
   t2= GetMicrosecondCount ()-t0;

   Print ( "Цикл округления 10 000 000 раз:  с (int) = " , IntegerToString (t1), "   с (#define) = " , IntegerToString (t2), " микросекунд" );
  }
//+------------------------------------------------------------------+


ve doldur

 #define _round(x) ( int )((x)+( 0.5 )) 
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart ()
  {
   ulong t0,t1,t2;
   int y0[],y1[];
   ArrayResize (y0, 10000000 );

   double x= 1.45 ;  

   for ( int i= 1 ;i< 10000000 ;i++)
     {
       if (( int )(x+ 0.5 )!=( int ) round (x)) Print ( "ой..." ,x);
      x+= 0.27 ;
       y0[i]+= 1 ; // !!!!!!!!!!!!!!
     }

   x= 1.45 ;
   t0= GetMicrosecondCount ();
   for ( int i= 0 ;i< 10000000 ;i++)
     {
      y0[i]=( int )(x+ 0.5 );
      x+= 0.27 ;
     }
   t1= GetMicrosecondCount ()-t0;

   x= 1.45 ;
   t0= GetMicrosecondCount ();
   for ( int i= 0 ;i< 10000000 ;i++)
     {
      y0[i]=_round(x);
      x+= 0.27 ;
     }
   t2= GetMicrosecondCount ()-t0;

   Print ( "Цикл округления 10 000 000 раз:  с (int) = " , IntegerToString (t1), "   с (#define) = " , IntegerToString (t2), " микросекунд" );
  }
//+------------------------------------------------------------------+
 
Ihor Herasko :

Ve eğer alır ve kontrol ederseniz? ))) int(45.27 + 0.5) 46'yı nasıl verecek? Aynı 45 kalacak.

Kabul et, yavaşla. Sözlerimi geri alıyorum...

 
Lilita Bogachkova :

Ancak dizi önceden veriyle doldurulmazsa hızın değişmesi yine de ilginçtir.


ve doldur

Her şey basit. Derleyici şu komutu yok sayar:
 y0[i]+= 0 ; // !!!!!!!!!!!!!!
çünkü hiçbir şeyi değiştirmez. Dizi başlatılmamış olarak kalır. Zaten başlatılmış bir diziye daha hızlı erişiliyor gibi görünüyor. İlk durumda, t1 hesaplandığında ikinci döngüde başlatma gerçekleşir ve bu nedenle t1, t2'den büyüktür. Ve ikinci durumda, başlatma ilk döngüde gerçekleşir. Bu nedenle, t1 ve t2 aynıdır.
 

"#define" ile bence daha uygun

 #define _floor(x) ( int )((x)) 
#define _ceil(x)  ( int )((x)+( 1 )) 
#define _round(x) ( int )((x)+( 0.5 )) 
 

Neden uzun atmıyorsun? Taşabilir olsa da, bir int'yi taşmak çok daha kolaydır.

Neden: