Get the number of decimal places of any numbers (not just quotes) bypassing Digits() in MQL4 and MQL5 - page 14

 

Can I brainstorm on a fast implementation of translating an array of structures (length multiple of sizeof(int)) to and from an int[] array?

Practical application is fast data exchange via resources. My variant is too universal, so it slows down.


These functions appeared in MT5

StructToCharArray
CharArrayToStruct

They do not exist in MT4 and probably will not. Therefore, we have to solve the problem with and without these functions (if they are useful).

The result will be useful to a large number of forum users here.


I have written a very simple template for brainstorming with my solution to this problem.

// Решения задачи: https://www.mql5.com/ru/forum/287618/page14#comment_9806429

#define  BENCH(A)                                                              \
{                                                                             \
  const ulong StartTime = GetMicrosecondCount();                              \
  A;                                                                          \
  Print("Time[" + #A + "] = " + (string)(GetMicrosecondCount() - StartTime)); \
}  

// Инициализация исходных данных
int InitData( MqlTick &Ticks[], const int Amount = 1 e6, const double Price = 1.2345)
{
  const int Size = ArrayResize(Ticks, Amount);
  
  for (int i = 0; i < Size; i++)
    Ticks[i].bid = Price;
    
  return(Size);
}

MqlTick TicksIn[];                  // Массив с исходными данными.
const int Init = InitData(TicksIn); // Инициализировали его.

// Проверка, что два массива совпадают.
bool IsCompare( const MqlTick &Ticks1[], const MqlTick &Ticks2[] )
{
  const int Size = ArraySize(Ticks1);  
  bool Res = (Size == ArraySize(Ticks2));
  
  for (int i = 0; (i < Size) && Res; i++)
    Res = (Ticks1[i].bid == Ticks2[i].bid);
    
  return(Res);
}

void OnStart()
{
  MqlTick TicksOut[];
  int Array[];
  
  BENCH(TicksToIntArray_fxsaber1(TicksIn, Array));  // Замерили конвертацию MqlTick[] -> int[].
  BENCH(IntArrayToTicks_fxsaber1(Array, TicksOut)); // Замерили конвертацию int[] -> MqlTick[].
  
  Print(IsCompare(TicksIn, TicksOut)); // Убедились, что тики на входе и выходе совпадают.
}

// Варианты реализаций
/***********************************************/
#include <TypeToBytes.mqh> // https://www.mql5.com/ru/code/16280

template <typename T1, typename T2>
int ArrayToArray( const T1 &Source[], T2 &Target[] )
{
  return(_ArrayCopy(Target, Source) / sizeof(T2));
}

// Перевод массива тиков в массив int[].
int TicksToIntArray_fxsaber1( const MqlTick &Ticks[], int &Array[] )
{
  return(ArrayToArray(Ticks, Array));
}

// Перевод массива int[] в массив тиков.
int IntArrayToTicks_fxsaber1( const int &Array[], MqlTick &Ticks[] )
{
  return(ArrayToArray(Array, Ticks));
}
/***********************************************/


Result

Time[TicksToIntArray_fxsaber1(TicksIn,Array)] = 2036468
Time[IntArrayToTicks_fxsaber1(Array,TicksOut)] = 2253915
true
 
Another variant
template <typename T>
union INTEGER
{
  T Data;
  int Integer[sizeof(T) / sizeof(int)];
};

// Перевод массива тиков в массив int[].
int TicksToIntArray_fxsaber2( const MqlTick &Ticks[], int &Array[] )
{
  INTEGER<MqlTick> TickInteger;
  
  const int Size1 = ArraySize(Ticks);
  const int Size2 = ArrayResize(Array, Size1 * sizeof(MqlTick) / sizeof(int));
  int j = 0;
  
  for (int i = 0; (i < Size1) && (j < Size2); i++)
  {
    TickInteger.Data = Ticks[i];
    
    j += ArrayCopy(Array, TickInteger.Integer, j);
  }    
  
  return(j);
}

// Перевод массива int[] в массив тиков.
int IntArrayToTicks_fxsaber2( const int &Array[], MqlTick &Ticks[] )
{
  INTEGER<MqlTick> TickInteger;
  
  const int Size1 = ArraySize(Array);
  const int Size2 = ArrayResize(Ticks, Size1 * sizeof(int) / sizeof(MqlTick));
  int j = 0;
  
  for (int i = 0; (i < Size1) && (j < Size2); j++)
  {
    i += ArrayCopy(TickInteger.Integer, Array, 0, i, sizeof(MqlTick) / sizeof(int));

    Ticks[j] = TickInteger.Data;        
  }    
  
  return(j);
}


Result

Time[TicksToIntArray_fxsaber2(TicksIn,Array)] = 91967
Time[IntArrayToTicks_fxsaber2(Array,TicksOut)] = 79630
true


Something considerably faster than the second option. There's probably no way to speed it up.

 

afast implementation of translating an array of structures (length multiple of sizeof(int)) to and from an int[] array?

Something like this

#property strict

template< typename S, typename T >
union UDT{
  UDT(){for(int i=0;i<sizeof(S)/sizeof(T);i++)t[i]=0;}
  UDT(S&src){s=src;}
  UDT(T&src[],int k=0){for(int i=0;i<sizeof(S)/sizeof(T);i++)t[i]=src[i+k];}
  void to(S&dst){dst=s;}
  void to(T&dst[],int k=0){for(int i=0;i<sizeof(S)/sizeof(T);i++)dst[i+k]=t[i];}
  S s; T t[sizeof(S)/sizeof(T)];};

template< typename S, typename T >
void StructToArray(S&src[],T&dst[]){
  ArrayResize(dst,ArraySize(src)*(sizeof(S)/sizeof(T)));
  for(int i=0;i<ArraySize(dst)/(sizeof(S)/sizeof(T));i++){UDT<S,T>u(src[i]);u.to(dst,i*(sizeof(S)/sizeof(T)));}}

template< typename S, typename T >
void ArrayToStruct(T&src[],S&dst[]){
  ArrayResize(dst,ArraySize(src)/(sizeof(S)/sizeof(T)));
  for(int i=0;i<ArraySize(dst);i++){UDT<S,T>u(src,i*(sizeof(S)/sizeof(T)));u.to(dst[i]);}}

void OnStart()
 {
  MqlRates rates[],r2[];
  int l[];
  CopyRates(_Symbol,_Period,0,10,rates);
  for(int i=0;i<10;i++)printf("open=%f, high=%f, low=%f, close=%f, time=%s",rates[i].open,rates[i].high,rates[i].low,rates[i].close,TimeToStr(rates[i].time));
  Print("");
  StructToArray(rates,l);
  ArrayToStruct(l,r2);
  for(int i=0;i<ArraySize(r2);i++)printf("open=%f, high=%f, low=%f, close=%f, time=%s",r2[i].open,r2[i].high,r2[i].low,r2[i].close,TimeToStr(r2[i].time));
 }  


 
Ilya Malev:

Something like this.

https://www.mql5.com/ru/forum/287618/page14#comment_9807465
TicksToIntArray_fxsaber2
Time[TicksToIntArray(TicksIn,Array)] = 735252
IntArrayToTicks_fxsaber2
Time[IntArrayToTicks(Array,TicksOut)] = 591458
true

https://www.mql5.com/ru/forum/287618/page14#comment_9808274
TicksToIntArray_antfx1
Time[TicksToIntArray(TicksIn,Array)] = 398796
IntArrayToTicks_antfx1
Time[IntArrayToTicks(Array,TicksOut)] = 296646
true

Well done! I'll get into the code, thanks.


Sounds like ArrayCopy is a real slowpoke.


ZY From run to run, I get very different results. For example, if I change the order of the Tests, everything almost gets reversed. Apparently, I need a more objective speed measurement.

Files:
 
Without much thought and debugging I wrote the first thing that came to mind, so there may be a lot of glitches. I have not encountered such a task myself before (although I have worked with unions extensively).
 
fxsaber:

ZZZ, ArrayCopy seems to be a bit of a drag.

I remember measuring on some local task, where I had to copy a small number of elements. Up to 16 elements the for loop was much faster than the ArrayCopy one, when the number of elements was larger, the ArrayCopy one was faster. Of course, the fastest variant without loops at all (like my functions on the previous page)

 
Ilya Malev:

The fastest way is to do it without loops at all (like my functions on the previous page).

I don't get it.

 
fxsaber:

I don't get it.

My point is that for(int i=0; i<5; i++) dst[i]=src[i]; works slower than dst[0]=src[0];dst[1]=src[1];dst[2]=src[2];dst[3]=src[3];dst[4]=src[4];

which is quite obvious in view of additional operations related to loop management)

And CopyArray works much faster than both of them, as I checked it now. Maybe it depends on situation, of course.

 

Yes, this will work much faster (replaced for where possible by ArrayCopy, the rest is the same):

template< typename S, typename T >
union UTS2{
  UTS2(){for(int i=0;i<sizeof(S)/sizeof(T);i++)t[i]=0;}
  UTS2(S&src){s=src;}
  UTS2(T&src[],int k=0){ArrayCopy(t,src,0,k,sizeof(S)/sizeof(T));}//for(int i=0;i<sizeof(S)/sizeof(T);i++)t[i]=src[i+k];}
  void to(S&dst){dst=s;}
  void to(T&dst[],int k=0){ArrayCopy(dst,t,k,0,sizeof(S)/sizeof(T));}//for(int i=0;i<sizeof(S)/sizeof(T);i++)dst[i+k]=t[i];}
  S s; T t[sizeof(S)/sizeof(T)];};

template< typename S, typename T >
void StructToArray2(S&src[],T&dst[]){
  ArrayResize(dst,ArraySize(src)*(sizeof(S)/sizeof(T)));
  for(int i=0;i<ArraySize(dst)/(sizeof(S)/sizeof(T));i++){UTS2<S,T>u(src[i]);u.to(dst,i*(sizeof(S)/sizeof(T)));}}

template< typename S, typename T >
void ArrayToStruct2(T&src[],S&dst[]){
  ArrayResize(dst,ArraySize(src)/(sizeof(S)/sizeof(T)));
  for(int i=0;i<ArraySize(dst);i++){UTS2<S,T>u(src,i*(sizeof(S)/sizeof(T)));u.to(dst[i]);}}

I told you, I wrote the first thing that came to mind without tests))

 
Ilya Malev:

And CopyArray, as I checked it now, works much faster than both options, it seems. Maybe it depends on the situation, of course.

If ArrayCopy() is made on the principle of Cish memmove(),

I think the speed of ArrayCopy() depends on the speed of memory allocation, if the intermediate buffer memory is ready for copying, ArrayCopy() will be executed very quickly, if the memory is not allocated, you will start requests to the operating system to allocate memory

you can try to test - make one call to ArrayCopy() with a large data volume, thereby preparing the buffer memory for exchange, and then make a loop with ArrayCopy() with a smaller data volume for copying and with the speed measurement

Reason: