Библиотеки: TicksShort - страница 3

 
fxsaber #:

Для Digits <= 5 проблема только у этих чисел.

Это обстоятельство, действительно, позволяет сделать очень дешевую распаковку при Digits <= 5.

 
fxsaber # :

Unfortunately, your function does not always work correctly.

You are right, we cannot depend on using DoubleAdvance() with 3-digits.

I modified your script a little to show more info.

#property script_show_inputs 
input  int  count = 1 e7;
input  int  digits = 3 ; 

void  OnStart () 
  { 
   static  const  double  _points10[] = { 1 , 1 e- 1 , 1 e- 2 , 1 e- 3 , 1 e- 4 , 1 e- 5 , 1 e- 6 , 1 e- 7 }; // MathPow(10, -digits) 
   static  const  double  _powers10[] = { 1 , 1 e1, 1 e2, 1 e3, 1 e4, 1 e5, 1 e6, 1 e7};         // MathPow(10, digits) 

   const  double  point = _points10[digits];
   const  double  power = _powers10[digits]; 

   int  err1 = 0 , err2 = 0 ;
   int  ulp1 = 0 , ulp2 = 0 ;
   int  advance_err = 0 ; 

   for ( int  i = 0  ; i < count; i++) 
     { 
      const  double  price  = NormalizeDouble (i * point, digits);
       const  double  price1 = ( int )(price / point + 0.1 ) * point;
       const  double  price2 = ( int )(price * power + 0.1 ) / power; 

      if (price1 != price) 
        { 
         err1 ++; 
         ulp1 += ( int )UlpDiff(price1, price); 

         if (price != DoubleAdvance(price1, - 1 )) 
            advance_err++; 
        } 

      if (price2 != price) 
        { 
         err2 ++; 
         ulp2 += ( int )UlpDiff(price2, price); 
        } 

     } 

   printf ( "Checking %d prices (%d digits) for round-trip errors:" , count, digits);
   printf ( "=== (int)(price/point+0.1) * point ===  Errors: %d (%.f%%), ULPs: %d, DoubleAdvance_err: %d" , err1, 100 .*err1/count, ulp1, advance_err);
   printf ( "=== (int)(price*power+0.1) / power ===  Errors: %d (%.f%%), ULPs: %d" , err2, 100 .*err2/count, ulp2); 
  } 

//+------------------------------------------------------------------+ 
//| Advances a floating-point number by a specified number of ULPs.  | 
//+------------------------------------------------------------------+ 
double  DoubleAdvance( const  double  value, const  long  distance) 
  { 
   if (!distance)
       return  value;
   union  _d { double  value; long  bits;} dbl; 
   dbl.value = value; 
   dbl.bits += distance; 
   return  dbl.value; 
  } 

//+------------------------------------------------------------------+ 
//| Returns the distance between two doubles a and b expressed as    | 
//| the number of gaps/bits/ULP (Units in the Last Place) between a  | 
//| and b. Note that the function returns a signed value indicating  | 
//| whether a > b or not.                                            | 
//+------------------------------------------------------------------+ 
long  UlpDiff( const  double  a, const  double  b) 
  { 
   long  bits1;
   union  _d { double  value; long  bits;} dbl; 
   dbl.value = a; 
   bits1 = dbl.bits; 
   dbl.value = b; 
   return  bits1 - dbl.bits; 
  } 

Results :

/* 
 Checking 10000000 prices (3 digits)  for round-trip errors: 
 === (int)(price/point+0.1) * point ===  Errors: 1339910 (13%), ULPs: 1339866, DoubleAdvance_err: 22 
 === (int)(price*power+0.1) / power ===  Errors: 788 (0%) , ULPs: 4 
 
 Checking 10000000 prices (5 digits) for round-trip errors: 
 === (int)(price/point+0.1) * point ===  Errors: 5235948 (52%), ULPs: 5235948, DoubleAdvance_err: 0 
 === (int)(price*power+0.1) / power ===  Errors: 108236 (1%) , ULPs: -28 

*/ 

MOD2  using DoubleAdvance is unreliable.

MOD1 using division by positive powers of 10 gives very low error rate (1%). The overhead of using NormalizeDouble() in these 1% of cases will be low too. 

That's way MOD1 should be the fastest / relaible. (One division operation should be faster than calling NormalizeDouble)

TickOut.bid = (this.bid = NormBid ? this.PriceBid / this.Pow
                                          : ::NormalizeDouble(this.PriceBid / this.Pow, 7/* this.digits*/));
Edited:
NormalizeDouble() is executed in 1% of cases
 
amrali #:

Таким образом, MOD1 должен быть самым быстрым и надёжным. (Одна операция деления должна быть быстрее, чем вызов NormalizeDouble)

Просьба показать свои результаты. У меня MOD1 не дает ускорения.

 
fxsaber #:

Please show your results. MOD1 doesn't give me any acceleration.

NormalizeDouble() is executed in 1% of cases, 99% it is a single division (faster than ND also). No need to check !
 
amrali #:
NormalizeDouble() is executed in 1% of cases, 99% it is a single division (faster than ND also). No need to check !
#define TICKS_SHORT_ALTERNATIVE
#include <fxsaber\TicksShort\TicksShort.mqh> // https://www.mql5.com/ru/code/61126

Compressed 789283080 bytes into 78928524 bytes ==> 10.00%
Compress performance: 3155 MB/s
Compress performance: 55.1 Ticks (millions)/sec.
Compress performance criterion: 551.4
Decompress performance: 3113 MB/s
Decompress performance: 54.4 Ticks (millions)/sec.
Decompress performance criterion: 544.1
Correct = true
#define TICKS_SHORT_ALTERNATIVE
#include <fxsaber\TicksShort\TicksShort_using_digits.mqh> // https://www.mql5.com/ru/forum/490384/page2#comment_57616652

Compressed 789285600 bytes into 78928776 bytes ==> 10.00%
Compress performance: 3594 MB/s
Compress performance: 62.8 Ticks (millions)/sec.
Compress performance criterion: 628.1
Decompress performance: 2994 MB/s
Decompress performance: 52.3 Ticks (millions)/sec.
Decompress performance criterion: 523.3
Correct = true
 
fxsaber #:
Tiny or no difference, it may be normal test fluctuations from run to run. I'd go with second one as the code and class members are much simpler. 
 
fxsaber #:

I tested many times, different symbol (3, 5 digits), longer periods: 

MOD1 is faster 10% than the last update.

#define TICKS_SHORT_ALTERNATIVE
#include <fxsaber\TicksShort\TicksShort.mqh> // https://www.mql5.com/ru/code/61126

Compressed 1448129700 bytes into 144813150 bytes ==> 10.00%
Compress performance: 6872 MB/s
Compress performance: 120.1 Ticks (millions)/sec.
Compress performance criterion: 1200.9
Decompress performance: 3163 MB/s
Decompress performance: 55.3 Ticks (millions)/sec.
Decompress performance criterion: 552.7
Correct = true

#define TICKS_SHORT_ALTERNATIVE
#include <fxsaber\TicksShort\TicksShort_using_digits.mqh> // https://www.mql5.com/ru/forum/490384/page2#comment_57616652

Compressed 1448129880 bytes into 144813168 bytes ==> 10.00%
Compress performance: 7578 MB/s
Compress performance: 132.4 Ticks (millions)/sec.
Compress performance criterion: 1324.3
Decompress performance: 3560 MB/s
Decompress performance: 62.2 Ticks (millions)/sec.
Decompress performance criterion: 622.2
Correct = true
In your test, I see that the difference in tick count between the two runs is very large, meaning that there was a larger time gap between the runs>
I suppose that the second run was in a time with a different system load.
 
amrali #:

В вашем тесте я вижу, что разница в количестве тиков между двумя запусками очень велика, что означает, что между запусками был больший временной разрыв.

Полагаю, что второй запуск был в период с другой загрузкой системы.

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Библиотеки: TicksShort

fxsaber, 2025.07.24 15:34

#define TICKS_SHORT_ALTERNATIVE
#include <fxsaber\TicksShort\TicksShort.mqh> // https://www.mql5.com/ru/code/61126

Compressed 789283080 bytes into 78928524 bytes ==> 10.00%
#define TICKS_SHORT_ALTERNATIVE
#include <fxsaber\TicksShort\TicksShort_using_digits.mqh> // https://www.mql5.com/ru/forum/490384/page2#comment_57616652

Compressed 789285600 bytes into 78928776 bytes ==> 10.00%
(789285600 - 789283080) / sizeof(MqlTick) = 43 ticks
 
amrali #:

Я проверял много раз, разные символы (3, 5 цифр), более длинные периоды:

MOD1 быстрее на 10% по сравнению с последним обновлением.

Возможно, зависимость от процессора и AVX. Моя конфигурация в самом низу следующего скриншота.
 
fxsaber # :
Probably CPU and AVX dependent. My config is at the very bottom of the next screenshot.
I think this is so.  Sorry you are right, I forgot that these are bytes not ticks.