Características da linguagem mql5, subtilezas e técnicas - página 122

 
Deparei-me com uma situação em que a mudança pode ser acelerada
#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))  
}


Resultado

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


A terceira opção (comutador) é constantemente mais lenta do que a segunda (apontadores de funções). Qual é a razão para isto?


ZS Lentamente. O terceiro interruptor é mais rápido do que o segundo interruptor. Tudo está bem.


Portanto, se tiver um conjunto imutável de indicadores de funções, será mais rápido se o substituir por um interruptor.

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


Assim, se tivermos um conjunto imutável de indicadores para funcionar, é mais rápido se o substituirmos por um interruptor.

Bem, neste caso é lógico, porque a matriz foi preenchida dinamicamente, o que significa verificações constantes da validade do ponteiro. Embora pudesse ser optimizada, claro...

Mas se a MQL suportasse a inicialização da matriz através de indicações constantes, seria provavelmente o mesmo.

p.s. O seu código não é de todo legível. Claro que compreendo que encontrará todas estas complexidades com macros convenientes, uma vez que as escreveu você mesmo, pelo que sabe o que fazem. Mas para um leitor externo, é apenas um puzzle. Penso que é pouco provável que você mesmo compreenda o que fez aqui em seis meses ) Pelo menos faça um comentário ou qualquer coisa ...

 
Alexey Navoykov:

p.s. O seu código é completamente ilegível. Claro, compreendo que se sinta confortável com todos estes artifícios com macros, porque você mesmo os escreveu, por isso sabe o que eles fazem. Mas para um leitor externo - é apenas um puzzle. Penso que é pouco provável que você mesmo compreenda o que lá fez em seis meses ) Pelo menos faça um comentário ou qualquer coisa ...

Caso contrário, seria uma confusão. Além disso, estava a fazer experiências com o número de transições. Sem macros, teria sido difícil. Acerca dos comentários adicionais - terei isso em conta no futuro.

 
fxsaber:

Caso contrário, teria sido uma confusão. Além disso, fiz experiências com o número de transições. Sem macros, teria sido difícil. Acerca dos comentários adicionais - terei isso em conta no futuro.

Por vezes é muito mais fácil desmontar uma expansão compreensível do que começar a desmontar um puzzle compacto e abandonar imediatamente esta actividade inútil.

 
Artyom Trishkin:

Por vezes é muito mais fácil desembaralhar uma peça de escrita compreensível do que começar a analisar um puzzle compacto e abandonar imediatamente a tarefa inútil em mãos.

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

Para além do que disse anteriormente, uma das causas mais comuns de desencontros no testador é uma inicialização defeituosa ou a sua falta.


Embora a inicialização de variáveis em falta seja simples, as matrizes são um pouco mais complicadas. Na maioria das vezes é a descoberta de situações em que o número de elementos de matriz aumenta que pode indicar um local problemático.


A fim de detectar esses potenciais problemas, pode inserir estas cordas no início do Expert Advisor

// Помогает найти причину потенциальной ошибочной инициализации
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 + ") = ")


Se a situação for apanhada, então a informação detalhada será escrita no diário de bordo e a corrida será interrompida.


SZZ Exemplo de aplicação.

 
Compreendo o redimensionamento, eu próprio utilizo frequentemente o mesmo método, mas e a inicialização? Como pode estar errado?
 
Alexey Navoykov:
Compreendo, eu próprio utilizo frequentemente este método, mas e a inicialização? Como pode ser inválido?

Por exemplo, o ArrayResize e o ArrayInitialize são misturados. Ou, por exemplo, o indicador executa o ArrayInitialize do tampão no OnInit, pensando erroneamente que o tampão é inicializado.

 
fxsaber:

Por exemplo, o ArrayResize e o ArrayInitialize são misturados.

Bem, este é um erro muito infantil. vale a pena um tal esforço para o encontrar?

 
Ilya Malev:

Bem, é um erro infantil. Vale a pena o esforço para o encontrar?

Encontrar qualquer erro requer esforço. Especialmente quando o código é grande e não é o seu.

Razão: