Features of the mql5 language, subtleties and tricks - page 303

 
fxsaber #:

I need a fast decompression of the compressed MqlTick. This option is unfortunately slow.

First, you should know that the conversation dbl -> float (packing) and then back from float -> double (unpack) could lose precision.

For example if you pack the price 1.1235, when unpacked the result could be 1.1234444.
Bench both NormalizeDouble() and optimized Round(). I think my function is fast enough.

Also division by / 1000 may be slow. Try the faster (3x) multiply * 0.001 if it makes difference. 
 
amrali #:
Such a task.
void OnStart()
{
  MqlTick NormTicks[]; // bid/ask - NormalizeDouble: CopyTicks.
  
  T CompressTicks[];
  Compress(NormTicks, CompressTicks) // Any performance
    
  MqlTick Ticks[];
  Decompress(CompressTicks, Ticks); // need it faster
  
  Print(sizeof(MqlTick) / sizeof(T)) // need more
  
  bool Res = true;
  
  for (uint i = ArraySize(Ticks); Res && (bool)i--;)
    Res = (Ticks[i].bid == NormTicks[i].bid) && (Ticks[i].ask == NormTicks[i].ask);
    
  Print(Res); // true
}
 

fxsaber #:
MqlTick

Print(sizeof(MqlTick) / sizeof(T)) // need more

It is very unreasonable to create a T structure for packing data, when each unpacked element of the MqlTick array will correspond to one packed element of the T structure array.
Packed data - for maximum density and performance should be a set of several data arrays (and ideally bit arrays) and a set of several index arrays (also bit arrays). Packing, as well as unpacking is a continuous sequential recurrent process from zero to the last index.
Ideally, on average, 4 bytes will be enough for one 60 byte MqlTick structure. I.e. 15 times packing. This is confirmed by the size of tkc files . And it seems to be the limit.
It is very strange why M1 MqlRates data (hcc files) are still not packed!!! I doubt that downloading and unpacking a packed file from an SSD drive would take longer than downloading an unpacked file that is say 5-6 times the size of the packed one.

 
Nikolai Semko #:

Each unpacked element of the MqlTick array will correspond to one packed element of the T structure array.

The following condition is not mandatory.
ArraySize(CompressTicks) == ArraySize(NormTicks)

That is, you can pack not just one MqlTick array element, but several at once.


I.e. in general this condition.

Print(ArraySize(NormTicks) * sizeof(MqlTick) / (ArraySize(CompressTicks) * sizeof(T))) // need more

But with such an uncomplicated initial formulation, people immediately fall away because of the long understanding.

 
fxsaber #:

I need a fast decompression of the compressed MqlTick. This option is unfortunately slow.

Try rounding to 5 digits instead of 8, to avoid tiny round-off errors:

    static  void decompress( const MqlTickBidAsk &tick, MqlTick &result)
    {
// result.bid = tick.bid; 
// result.ask = tick.ask; 
      result.bid = :: NormalizeDouble (tick.bid, 5 );
      result.ask = :: NormalizeDouble (tick.ask, 5 ); 
      result.last = 0 ;
      result.time_msc = tick.time_msc;
      result.time = ( datetime )( tick.time_msc / 1000 );
      result.flags = tick.flags;
      result.volume = 0 ;
      result.volume_real = 0 ;
    }
 
amrali #:

Try rounding to 5 digits instead of 8 to avoid tiny rounding errors:

Yes, in that context, the digit matters.

 
Please clarify with bitwise operations.
void OnStart()
{
  ushort Num = 0;
    
  Print(typename(Num >> 1)); // int ?!
  
  Num >>= 1; // A double conversion is done here: ushort -> int -> ushort?
  
  Num = Num >> 1; // Why isn't there a warning that a signed int goes to unsigned ushort?
}


Why does a bitwise operation lead to the creation of an int-variable?

How to do bitwise operations cheaply?


fxsaber operations.

Is this correct?

void OnStart()
{
  int Num = -1;
  
  Print(Num >> 8); // -1
}


Uploaded to this thread as it is autotranslate.

 
fxsaber #:
Is that correct?

Yes, the shift is arithmetic, the code is additional.

0xFFFFFFFFFFFF no matter how much you shift it, 0xFFFFFFFFFFFF will remain.

Если же сдвигаемое значение имеет знаковый тип, то осуществляется арифметический сдвиг вправо, то есть освобождающиеся слева разряды будут заполняться значением знакового бита (если число положительное, то значение знакового бита равно 0, если число отрицательное, то значение знакового бита равно 1)

https://www.mql5.com/en/docs/basis/operations/bit

 
fxsaber #:

Why does a bitwise operation lead to the creation of an int-variable?

No explanation!

The bug (?!) shows in the intermediate results ONLY (for all bitwise operators).

However, assignment (Num >>= 1) works as expected, (luckily).

void OnStart()
{
  Print(typename((uchar   (3)) >> 1));      // int ?!
  Print(typename((ushort  (3)) >> 1));      // int ?!
  Print(typename((uint    (3)) >> 1));      // uint
  Print(typename((ulong   (3)) >> 1));      // ulong
  Print(typename((char    (3)) >> 1));      // int ?!
  Print(typename((short   (3)) >> 1));      // int ?!
  Print(typename((int     (3)) >> 1));      // int
  Print(typename((long    (3)) >> 1));      // long
  Print(typename((bool    (3)) >> 1));      // int ?!
  Print(typename((color   (3)) >> 1));      // int ?!
  Print(typename((datetime(3)) >> 1));      // datetime

  Print(typename((uchar   (3)) << 1));      // int ?!
  Print(typename((ushort  (3)) << 1));      // int ?!
  Print(typename((uint    (3)) << 1));      // uint
  Print(typename((ulong   (3)) << 1));      // ulong
  Print(typename((char    (3)) << 1));      // int ?!
  Print(typename((short   (3)) << 1));      // int ?!
  Print(typename((int     (3)) << 1));      // int
  Print(typename((long    (3)) << 1));      // long
  Print(typename((bool    (3)) << 1));      // int ?!
  Print(typename((color   (3)) << 1));      // int ?!
  Print(typename((datetime(3)) << 1));      // datetime

  Print(typename((uchar   (3)) & 1));      // int ?!
  Print(typename((ushort  (3)) & 1));      // int ?!
  Print(typename((uint    (3)) & 1));      // uint
  Print(typename((ulong   (3)) & 1));      // ulong
  Print(typename((char    (3)) & 1));      // int ?!
  Print(typename((short   (3)) & 1));      // int ?!
  Print(typename((int     (3)) & 1));      // int
  Print(typename((long    (3)) & 1));      // long
  Print(typename((bool    (3)) & 1));      // int ?!
  Print(typename((color   (3)) & 1));      // int ?!
  Print(typename((datetime(3)) & 1));      // datetime

  Print(typename((uchar   (3)) | 1));      // int ?!
  Print(typename((ushort  (3)) | 1));      // int ?!
  Print(typename((uint    (3)) | 1));      // uint
  Print(typename((ulong   (3)) | 1));      // ulong
  Print(typename((char    (3)) | 1));      // int ?!
  Print(typename((short   (3)) | 1));      // int ?!
  Print(typename((int     (3)) | 1));      // int
  Print(typename((long    (3)) | 1));      // long
  Print(typename((bool    (3)) | 1));      // int ?!
  Print(typename((color   (3)) | 1));      // int ?!
  Print(typename((datetime(3)) | 1));      // datetime
}
 
JRandomTrader #:

Yes, the shift is arithmetic, the code is optional.

0xFFFFFFFFFFFF no matter how much you shift it, 0xFFFFFFFFFFFF remains.

https://www.mql5.com/en/docs/basis/operations/bit

Thanks, missed it when reading the help.