绕过MQL4和MQL5中的Digits(),获取任何数字的小数位数(不仅仅是引号)。 - 页 14

 

我可以集思广益,研究如何快速实现将一个结构数组(长度为sizeof(int)的倍数)转换为int[]数组并从该数组中转换 出来?

实际应用是通过资源快速交换数据。我的变体 太普遍了,所以速度变慢了。


这些功能出现在MT5中

StructToCharArray
CharArrayToStruct

它们在MT4中不存在,可能也不会存在。所以我们必须在有和没有这些功能的情况下解决问题(如果它们是有用的)。

这个结果将对这里的大量论坛用户有用。


我写了一个非常简单的模板,用于头脑风暴,其中有我对这个问题的解决方案。

// Решения задачи: 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));
}
/***********************************************/


结果

Time[TicksToIntArray_fxsaber1(TicksIn,Array)] = 2036468
Time[IntArrayToTicks_fxsaber1(Array,TicksOut)] = 2253915
true
 
另一个变体
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);
}


结果

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


比第二个选项快得多的东西。可能没有办法加快它的速度。

 

将一个结构数组(长度为sizeof(int)的倍数)转换为一个int[]数组的快速实现

类似这样的事情

#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:

类似这样的事情。

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

干得好!我将进入代码,谢谢。


听起来ArrayCopy 是一个真正的慢郎中。


ZY从运行到运行,我得到非常不同的结果。例如,如果我改变测试的顺序,一切几乎都会被颠覆。显然,我需要一个更客观的速度测量。

附加的文件:
 
在没有多加思考和调试的情况下,我写了第一个想到的东西,所以可能会有很多小毛病。我自己以前没有遇到过这样的任务(尽管我曾广泛地与工会合作)。
 
fxsaber:

ZZZ,ArrayCopy似乎有点拖沓。

我记得在一些本地任务中进行测量,我必须复制少量的元素。在16个元素以下,for循环比ArrayCopy 快得多,当元素数更多时,ArrayCopy更快。当然,最快的变体是完全没有循环的(就像我在上一页的函数)。

 
Ilya Malev:

最快的方法是完全不用循环(就像我在前一页的函数)。

我不明白。

 
fxsaber:

我不明白。

我的观点是,for(int i=0; i<5; i++) dst[i]=src[i]; 比dst[0]=src[0];dst[1]=src[1];dst[2]=src[2];dst[3]=src[3];dst[4]=src[4] 工作得慢。

考虑到与循环管理有关的额外操作,这一点非常明显)

而CopyArray的工作速度比它们都快得多,因为我现在检查了。也许这取决于情况,当然。

 

是的,这将工作得更 快(在可能的情况下,用ArrayCopy 代替,其余的都一样)。

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]);}}

我告诉过你,我写的是第一个想到的东西,没有测试))。

 
Ilya Malev:

而CopyArray,正如我现在检查的那样,似乎比这两个选项都快得多。当然,也许这要看情况而定。

如果ArrayCopy()是根据Cish memmove()的原则进行的。

我认为ArrayCopy()的速度取决于内存分配的速度,如果中间缓冲区的内存已经准备好供复制,ArrayCopy()将很快被执行,如果内存没有分配,你将开始请求操作系统分配内存

你可以试着测试一下--用大的数据量调用ArrayCopy(),从而为交换准备好缓冲内存,然后用ArrayCopy()做一个循环,用较小的数据量进行复制,用速度计进行测试。