Ermitteln der Anzahl der Dezimalstellen beliebiger Zahlen (nicht nur Anführungszeichen) unter Umgehung von Digits() in MQL4 und MQL5 - Seite 14

 

Kann ich Brainstorming auf eine schnelle Implementierung der Übersetzung eines Arrays von Strukturen (Länge Vielfache von sizeof(int)) zu und von einem int[] Array?

Praktische Anwendung ist der schnelle Datenaustausch über Ressourcen. Meine Variante ist zu universell, so dass sie sich verlangsamt.


Diese Funktionen wurden in MT5 eingeführt

StructToCharArray
CharArrayToStruct

Diese gibt es in MT4 nicht und wird es wahrscheinlich auch nicht geben. Wir müssen also das Problem mit und ohne diese Funktionen lösen (falls sie nützlich sind).

Das Ergebnis wird für eine große Zahl von Forumsnutzern hier nützlich sein.


Ich habe eine sehr einfache Vorlage für ein Brainstorming mit meiner Lösung für dieses Problem geschrieben.

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


Ergebnis

Time[TicksToIntArray_fxsaber1(TicksIn,Array)] = 2036468
Time[IntArrayToTicks_fxsaber1(Array,TicksOut)] = 2253915
true
 
Eine andere Variante
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);
}


Ergebnis

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


Etwas, das wesentlich schneller ist als die zweite Option. Es gibt wahrscheinlich keine Möglichkeit, dies zu beschleunigen.

 

eineschnelle Implementierung der Umwandlung eines Arrays von Strukturen (Länge ein Vielfaches von sizeof(int)) in und aus einem int[]-Array?

Etwa so

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

Etwa so.

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

Gut gemacht! Ich werde mich mit dem Code befassen, danke.


Klingt so, als ob ArrayCopy ein echter Langweiler ist.


ZY Von Lauf zu Lauf erhalte ich sehr unterschiedliche Ergebnisse. Wenn ich zum Beispiel die Reihenfolge der Tests ändere, wird fast alles umgedreht. Offensichtlich ist eine objektivere Geschwindigkeitsmessung erforderlich.

Dateien:
 
Ohne viel nachzudenken und zu debuggen, habe ich das erste geschrieben, was mir in den Sinn kam, daher kann es eine Menge Fehler geben. Ich bin selbst noch nie mit einer solchen Aufgabe konfrontiert worden (obwohl ich viel mit Gewerkschaften gearbeitet habe).
 
fxsaber:

ZZZ, ArrayCopy scheint ein bisschen lästig zu sein.

Ich erinnere mich, dass ich an einer lokalen Aufgabe gemessen habe, bei der ich eine kleine Anzahl von Elementen kopieren musste. Bis zu 16 Elementen war die for-Schleife viel schneller als die ArrayCopy-Schleife, wenn die Anzahl der Elemente größer war, war die ArrayCopy-Schleife schneller. Natürlich ist die schnellste Variante ganz ohne Schleifen (wie meine Funktionen auf der vorherigen Seite)

 
Ilya Malev:

Am schnellsten geht es, wenn Sie ganz ohne Schleifen auskommen (wie meine Funktionen auf der vorherigen Seite).

Das verstehe ich nicht.

 
fxsaber:

Das verstehe ich nicht.

Mein Punkt ist, dass for(int i=0; i<5; i++) dst[i]=src[i]; langsamer arbeitet als dst[0]=src[0];dst[1]=src[1];dst[2]=src[2];dst[3]=src[3];dst[4]=src[4];

was in Anbetracht der zusätzlichen Operationen im Zusammenhang mit der Schleifensteuerung ziemlich offensichtlich ist)

Und CopyArray funktioniert viel schneller als beide, wie ich es jetzt überprüft habe. Vielleicht hängt es natürlich von der Situation ab.

 

Ja, dies wird viel schneller funktionieren (wo möglich ersetzt durch ArrayCopy, der Rest ist derselbe):

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

Wie gesagt, ich habe das Erste geschrieben, was mir in den Sinn kam, ohne Tests))

 
Ilya Malev:

Und CopyArray, wie ich es jetzt überprüft habe, funktioniert viel schneller als beide Optionen, so scheint es. Das hängt natürlich von der jeweiligen Situation ab.

Wenn ArrayCopy() nach dem Prinzip von Cish memmove() durchgeführt wird,

Ich denke, die Geschwindigkeit von ArrayCopy() hängt von der Geschwindigkeit der Speicherzuweisung ab, wenn der Zwischenpufferspeicher zum Kopieren bereit ist, wird ArrayCopy() sehr schnell ausgeführt, wenn der Speicher nicht zugewiesen ist, werden Sie Anfragen an das Betriebssystem starten, um Speicher zuzuweisen

Sie können versuchen zu testen - machen Sie einen Aufruf von ArrayCopy() mit einer großen Datenmenge, wodurch der Pufferspeicher für den Austausch vorbereitet wird, und machen Sie dann eine Schleife mit ArrayCopy() mit einer kleineren Datenmenge zum Kopieren und mit dem Geschwindigkeitsmesser