Obtenir le nombre de décimales de n'importe quel nombre (pas seulement les guillemets) en contournant Digits() dans MQL4 et MQL5 - page 14

 

Puis-je réfléchir à une implémentation rapide de la traduction d'un tableau de structures (longueur multiple de sizeof(int)) vers et depuis un tableau int[]?

L'application pratique est l'échange rapide de données via les ressources. Ma variante est trop universelle, ce qui la ralentit.


Ces fonctions sont apparues dans MT5

StructToCharArray
CharArrayToStruct

Ils n'existent pas dans MT4 et n'existeront probablement pas. Par conséquent, nous devons résoudre le problème avec et sans ces fonctions (si elles sont utiles).

Le résultat sera utile à un grand nombre d'utilisateurs du forum ici.


J'ai écrit un modèle très simple pour le brainstorming avec ma solution à ce problème.

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


Résultat

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


Résultat

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


Quelque chose de beaucoup plus rapide que la deuxième option. Il n'y a probablement aucun moyen d'accélérer le processus.

 

uneimplémentation rapide de la traduction d'un tableau de structures (longueur multiple de sizeof(int)) vers et depuis un tableau int[]?

Quelque chose comme ça

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

Quelque chose comme ça.

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

Bien joué ! Je vais m'occuper du code, merci.


On dirait que ArrayCopy est vraiment lent.


ZY D'une course à l'autre, j'obtiens des résultats très différents. Par exemple, si je change l'ordre des tests, tout s'inverse presque. Apparemment, j'ai besoin d'une mesure de vitesse plus objective.

Dossiers :
 
Sans beaucoup de réflexion et de débogage, j'ai écrit la première chose qui m'est venue à l'esprit, donc il peut y avoir beaucoup de problèmes. Je n'ai jamais été confronté moi-même à une telle tâche (bien que j'aie beaucoup travaillé avec des syndicats).
 
fxsaber:

ZZZ, ArrayCopy semble être un peu un frein.

Je me souviens avoir mesuré une tâche locale, où je devais copier un petit nombre d'éléments. Jusqu'à 16 éléments, la boucle for était beaucoup plus rapide que la boucle ArrayCopy. Lorsque le nombre d'éléments était plus important, la boucle ArrayCopy était plus rapide. Bien sûr, la variante la plus rapide sans aucune boucle (comme mes fonctions à la page précédente)

 
Ilya Malev:

Le moyen le plus rapide est de le faire sans aucune boucle (comme mes fonctions de la page précédente).

Je ne comprends pas.

 
fxsaber:

Je ne comprends pas.

Ce que je veux dire, c'est que for(int i=0 ; i<5 ; i++) dst[i]=src[i] ; fonctionne plus lentement que dst[0]=src[0];dst[1]=src[1];dst[2]=src[2];dst[3]=src[3];dst[4]=src[4] ;

ce qui est assez évident au vu des opérations supplémentaires liées au contrôle de la boucle)

Et CopyArray fonctionne beaucoup plus rapidement que les deux, comme je l'ai vérifié maintenant. Cela dépend peut-être de la situation, bien sûr.

 

Oui, cela fonctionnera beaucoup plus rapidement (remplacé dans la mesure du possible par ArrayCopy, le reste est identique) :

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

Je vous l'ai dit, j'ai écrit la première chose qui m'est venue à l'esprit sans faire de tests ;))

 
Ilya Malev:

Et CopyArray, comme je l'ai vérifié maintenant, fonctionne beaucoup plus rapidement que les deux options, il me semble. Cela dépend peut-être de la situation, bien sûr.

Si ArrayCopy() est fait sur le principe de Cish memmove(),

Je pense que la vitesse d'ArrayCopy() dépend de la vitesse d'allocation de la mémoire, si la mémoire tampon intermédiaire est prête à être copiée, ArrayCopy() sera exécuté très rapidement, si la mémoire n'est pas allouée, vous commencerez à demander au système d'exploitation d'allouer la mémoire

vous pouvez essayer de tester - faire un appel à ArrayCopy() avec un grand volume de données, préparant ainsi la mémoire tampon pour l'échange, et ensuite faire une boucle avec ArrayCopy() avec un plus petit volume de données pour la copie et avec la mesure de vitesse

Raison: