Merkmale der Sprache mql5, Feinheiten und Techniken - Seite 122

 
Ich bin über eine Situation gestolpert, in der der Wechsel beschleunigt werden kann
#define  MACROS2 \
  MACROS(0)     \
  MACROS(1)     \
  MACROS(2)     \
  MACROS(3)     \
  MACROS(4)     \
  MACROS(5)     \
  MACROS(6)     \
  MACROS(7)     \
  MACROS(8)     \
  MACROS(9)

double Math( const double Value ) { return(MathSqrt(Value)); }

typedef double(*SUMFUNC)( void );

#define  MACROS(A) double SumFunc##A() { return(Math(A + 1)); }
  MACROS2
#undef  MACROS

SUMFUNC SumFunc[10];

bool Init()
{
#define  MACROS(A) SumFunc[A] = SumFunc##A;
   MACROS2
#undef  MACROS
  
  return(true);
}

const bool Init = Init();

// Через switch
void SwitchFunc1( const int Value, double &Sum )
{    
  switch (Value)
  {
  #define  MACROS(A) case A: Sum += Math(A + 1); break;
    MACROS2
  #undef  MACROS    
  }
}

// Через массив указателей на функции
void SwitchFunc2( const int Value, double &Sum )
{
  Sum += SumFunc[Value]();
}

// Через switch2
void SwitchFunc3( const int Value, double &Sum )
{    
  switch (Value)
  {
  #define  MACROS(A) case A: Sum += SumFunc##A(); break;
    MACROS2
  #undef  MACROS    
  }
}

typedef void(*SWITCHFUNC)( const int, double& );

void Bench( SWITCHFUNC SwitchFunc )
{
  double Sum = 0;
  
  MathSrand(0);
  
  for (int i = 0; i < 1 e8; i++)
    SwitchFunc(MathRand() % 10, Sum);
    
  Print(Sum);
}

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

void OnStart()
{
  BENCH(Bench(SwitchFunc1))
  BENCH(Bench(SwitchFunc2))  
  BENCH(Bench(SwitchFunc3))  
}


Ergebnis

224677638.4805779
Time[Bench(SwitchFunc1)] = 635995
224677638.4805779
Time[Bench(SwitchFunc2)] = 1646031
224677638.4805779
Time[Bench(SwitchFunc3)] = 1593283


Die dritte Option (Schalter) ist durchweg langsamer als die zweite (Funktionszeiger). Was ist der Grund dafür?


ZS Langsam. Der dritte Schalter ist schneller als der zweite Schalter. Alles ist in Ordnung.


Wenn Sie also ein unveränderliches Array von Zeigern auf Funktionen haben, wird es schneller sein, wenn Sie es durch switch ersetzen.

Почему Switch/Case, а не If/Else If?
  • 2009.06.22
  • OB OB
  • qaru.site
Этот вопрос в основном указывается на C/С++, но я думаю, что другие языки также актуальны. Я не могу понять, почему используется параметр switch/case вместо if/else if. Мне очень нравится использование goto's и приводит к тому же виду беспорядочного кода, в то время как те же результаты могут быть достигнуты с if/else, если более организованным...
 
fxsaber:


Wenn wir also ein unveränderliches Array von Zeigern auf Funktionen haben, ist es schneller, wenn wir es durch switch ersetzen.

Nun, in diesem Fall ist es logisch, weil das Array dynamisch gefüllt wurde, was bedeutet, dass die Gültigkeit der Zeiger ständig überprüft wird. Obwohl es natürlich optimiert werden könnte...

Aber wenn MQL Array-Initialisierung durch konstante Zeiger unterstützt, würde es wahrscheinlich das gleiche sein.

p.s. Ihr Code ist überhaupt nicht lesbar. Natürlich verstehe ich, dass Sie mit all diesen Feinheiten der Makros vertraut sind, weil Sie sie selbst geschrieben haben und daher wissen, was sie bewirken. Aber für einen externen Leser ist es einfach ein Rätsel. Ich denke, Sie selbst werden wohl kaum verstehen, was Sie hier in sechs Monaten angerichtet haben ) Machen Sie wenigstens einen Kommentar oder so ...

 
Alexey Navoykov:

p.s. Ihr Code ist völlig unleserlich. Natürlich verstehe ich, dass Sie mit all diesen Tricks mit Makros gut zurechtkommen, weil Sie sie selbst geschrieben haben und daher wissen, was sie bewirken. Aber für einen externen Leser ist es einfach ein Rätsel. Ich denke, Sie selbst werden wohl kaum verstehen, was Sie dort in sechs Monaten gemacht haben... Machen Sie wenigstens einen Kommentar oder so.

Sonst wärst du ein Wrack. Außerdem habe ich mit der Anzahl der Übergänge experimentiert. Ohne Makros wäre es schwierig gewesen. Was die zusätzlichen Kommentare betrifft, so werde ich sie in Zukunft berücksichtigen.

 
fxsaber:

Sonst wäre es eine Katastrophe gewesen. Darüber hinaus habe ich mit der Anzahl der Übergänge experimentiert. Ohne Makros wäre es schwierig gewesen. Was die zusätzlichen Kommentare betrifft, so werde ich sie in Zukunft berücksichtigen.

Manchmal ist es viel einfacher, einen verständlichen Wust zu zerlegen, als ein kompaktes Puzzle zu zerlegen und diese sinnlose Tätigkeit sofort wieder aufzugeben.

 
Artyom Trishkin:

Manchmal ist es viel einfacher, einen verständlichen Text zu entschlüsseln, als ein kompaktes Puzzle zu entziffern und die sinnlose Aufgabe sofort aufzugeben.

double Math( const double Value ) { return(MathSqrt(Value)); }

typedef double(*SUMFUNC)( void );

double SumFunc0() { return(Math(0 + 1)); }
double SumFunc1() { return(Math(1 + 1)); }
double SumFunc2() { return(Math(2 + 1)); }
double SumFunc3() { return(Math(3 + 1)); }
double SumFunc4() { return(Math(4 + 1)); }
double SumFunc5() { return(Math(5 + 1)); }
double SumFunc6() { return(Math(6 + 1)); }
double SumFunc7() { return(Math(7 + 1)); }
double SumFunc8() { return(Math(8 + 1)); }
double SumFunc9() { return(Math(9 + 1)); }

SUMFUNC SumFunc[10];

bool Init()
{
  SumFunc[0] = SumFunc0;
  SumFunc[1] = SumFunc1;
  SumFunc[2] = SumFunc2;
  SumFunc[3] = SumFunc3;
  SumFunc[4] = SumFunc4;
  SumFunc[5] = SumFunc5;
  SumFunc[6] = SumFunc6;
  SumFunc[7] = SumFunc7;
  SumFunc[8] = SumFunc8;
  SumFunc[9] = SumFunc9;
  
  return(true);
}

const bool Init = Init();

// Через switch
void SwitchFunc1( const int Value, double &Sum )
{    
  switch (Value)
  {
  case 0: Sum += Math(0 + 1); break;
  case 1: Sum += Math(1 + 1); break;
  case 2: Sum += Math(2 + 1); break;
  case 3: Sum += Math(3 + 1); break;
  case 4: Sum += Math(4 + 1); break;
  case 5: Sum += Math(5 + 1); break;
  case 6: Sum += Math(6 + 1); break;
  case 7: Sum += Math(7 + 1); break;
  case 8: Sum += Math(8 + 1); break;
  case 9: Sum += Math(9 + 1); break;
  }
}

// Через массив указателей на функции
void SwitchFunc2( const int Value, double &Sum )
{
  Sum += SumFunc[Value]();
}

// Через switch2
void SwitchFunc3( const int Value, double &Sum )
{    
  switch (Value)
  {
  case 0: Sum += SumFunc0(); break;
  case 1: Sum += SumFunc1(); break;
  case 2: Sum += SumFunc2(); break;
  case 3: Sum += SumFunc3(); break;
  case 4: Sum += SumFunc4(); break;
  case 5: Sum += SumFunc5(); break;
  case 6: Sum += SumFunc6(); break;
  case 7: Sum += SumFunc7(); break;
  case 8: Sum += SumFunc8(); break;
  case 9: Sum += SumFunc9(); break;
  }
}

typedef void(*SWITCHFUNC)( const int, double& );

void Bench( SWITCHFUNC SwitchFunc )
{
  double Sum = 0;
  
  MathSrand(0);
  
  for (int i = 0; i < 1 e8; i++)
    SwitchFunc(MathRand() % 10, Sum);
    
  Print(Sum);
}

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

void OnStart()
{
  BENCH(Bench(SwitchFunc1))
  BENCH(Bench(SwitchFunc2))  
  BENCH(Bench(SwitchFunc3))  
}
 

Darüber hinaus ist eine der häufigsten Ursachen für fehlerhafte Läufe im Prüfgerät eine fehlerhafte oder fehlende Initialisierung.


Während die Initialisierung fehlender Variablen einfach ist, sind Arrays ein wenig komplizierter. Meistens ist es das Auffinden von Situationen, in denen die Anzahl der Array-Elemente zunimmt, die auf eine Problemstelle hinweisen können.


Um solche potenziellen Probleme abzufangen, können Sie diese Zeichenfolgen am Anfang des Expert Advisors einfügen

// Помогает найти причину потенциальной ошибочной инициализации
template <typename T>
int ArrayResize2( T &Array[], const int NewSize, const string Str )
{
  const int PrevSize = ArraySize(Array);
  const int Res = ArrayResize(Array, NewSize);
  
  if ((PrevSize < NewSize) || (Res != NewSize))
  {
  #define  TOSTRING(A) ", " + #A + " = " + (string)(A)
    Print(Str + (string)Res + TOSTRING(PrevSize) + TOSTRING(NewSize));
  #undef  TOSTRING     
  
    TesterStop();
  }
  
  return(Res);
}

// Вариант с Reserve != 0 не предусмотрен
#define ArrayResize(A,B) ArrayResize2(A, B, __FUNCSIG__ + ", Line = " + (string)__LINE__ + \
                                            ": ArrayResize(" + #A + ", " + #B + ") = ")
// Помогает найти причину потенциальной ошибочной инициализации
template <typename T1, typename T2>
int ArrayInitialize2( T1 &Array[], const T2 Value, const string Str )
{
  const int Res = ArrayInitialize(Array, Value);
  
  if (!ArraySize(Array) || !Res)
  {
  #define  TOSTRING(A) ", " + #A + " = " + (string)(A)
    Print(Str + (string)Res + TOSTRING(ArraySize(Array)));
  #undef  TOSTRING     
  
    TesterStop();
  }
  
  return(Res);
}

#define ArrayInitialize(A,B) ArrayInitialize2(A, B, __FUNCSIG__ + ", Line = " + (string)__LINE__ +  \
                                                    ": ArrayInitialize(" + #A + ", " + #B + ") = ")


Wenn die Situation erkannt wird, werden die detaillierten Informationen in das Protokoll geschrieben und der Lauf wird beendet.


SZZ Beispielanwendung.

 
Das mit der Größenanpassung verstehe ich, ich verwende selbst oft die gleiche Methode, aber was ist mit der Initialisierung? Wie kann das falsch sein?
 
Alexey Navoykov:
Ich verstehe, ich verwende diese Methode selbst oft, aber was ist mit der Initialisierung? Wie kann sie ungültig sein?

Zum Beispiel werden ArrayResize und ArrayInitialize verwechselt. Oder der Indikator führt z.B. ArrayInitialize des Puffers bei OnInit aus und denkt fälschlicherweise, dass der Puffer initialisiert ist.

 
fxsaber:

Zum Beispiel werden ArrayResize und ArrayInitialize verwechselt.

Nun, das ist ein sehr kindischer Fehler. Ist es die Mühe wert, ihn zu finden?

 
Ilya Malev:

Nun, es ist ein kindischer Fehler. Lohnt es sich, ihn zu suchen?

Das Auffinden von Fehlern ist mühsam. Vor allem, wenn der Code umfangreich ist und nicht von Ihnen stammt.