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

잘했어! 코드를 살펴보겠습니다. 감사합니다.


ZY 유사, ArrayCopy - 여전히 브레이크입니다.


ZYY 처음부터 매우 다른 결과가 나타납니다. 예를 들어 테스트의 순서를 변경하면 모든 것이 거의 역전됩니다. 분명히, 더 객관적인 속도 측정이 필요합니다.

파일:
 
많은 생각과 디버깅 없이 가장 먼저 떠오른 것을 썼으니 아마도 글리치로 가득 차 있을 것입니다. 나 자신은 (노조와 긴밀히 협력했지만) 전에 그런 일에 직면한 적이 없습니다.
 
fxsaber :

ZY 유사, 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는 두 옵션보다 훨씬 빠르게 작동하는 것 같습니다. 물론 상황에 따라 다를 수 있습니다.

Sish의 memmove() 원리에 따라 ArrayCopy()를 만들었다면,

그러면 ArrayCopy()의 속도는 메모리 할당 속도에 달려 있다고 생각하는데, 복사를 위한 중간 버퍼의 메모리가 준비되어 있으면 ArrayCopy()가 매우 빨리 실행되고 메모리가 할당되지 않으면 요청 OS가 메모리를 할당 하기 시작합니다.

당신은 테스트를 시도할 수 있습니다 - 많은 양의 데이터로 ArrayCopy()를 한 번 호출하여 교환을 위한 버퍼 메모리를 준비한 다음 복사할 더 적은 양의 데이터로 ArrayCopy()로 루프를 만들고 속도를 측정합니다.