Implémentations alternatives de fonctions/approches standard - page 3

 
fxsaber:
Il s'avère que #import ex5 est le mal de l'optimisation.

En termes de capacité d'optimisation globale, oui.

Nous avons un inlining assez agressif sans chercher à rendre le code plus petit. Ainsi, en mode d'optimisation globale, nous générons un très bon code.

Cela se voit au moment de la compilation, où nous plaçons la vitesse résultante en tête de liste.

 
prostotrader:

fxsaber

Il y a une erreur dans votre code

Merci, je l'ai corrigé.
double MyNormalizeDouble( const double Value, const uint digits )
{
  static const double Points[] = {1.0 e-0, 1.0 e-1, 1.0 e-2, 1.0 e-3, 1.0 e-4, 1.0 e-5, 1.0 e-6, 1.0 e-7, 1.0 e-8};
  const double point = digits > 8 ? 1.0 e-8 : Points[digits];

  return((long)((Value > 0) ? Value / point + HALF_PLUS : Value / point - HALF_PLUS) * point);
}
 
fxsaber:
Merci, corrigé.

C'est toujours une erreur.

Il devrait y avoir un 5 à la fin.

 
prostotrader:

Toujours une erreur

Ce n'est pas une erreur, c'est un arrondi. C'est exactement ce que fait la version standard.
 
fxsaber:
Il ne s'agit pas d'une erreur, mais d'un arrondi. C'est ainsi que la version standard procède.
J'ai fait une erreur avec la mauvaise capture d'écran, regardez à nouveau (remplacer l'image).
 

Voici le code que vous pouvez tester

//+------------------------------------------------------------------+
//|                                                         Test.mq5 |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2016, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#define  EPSILON (1.0 e-7 + 1.0 e-13)
#define  HALF_PLUS  (0.5 + EPSILON)
#property indicator_separate_window
#property indicator_plots   1
#property indicator_buffers 1
double d_value = 12345.012345;
//
double MyNormalizeDouble( const double Value, const uint digits )
{
  static const double Points[] = {1.0 e-0, 1.0 e-1, 1.0 e-2, 1.0 e-3, 1.0 e-4, 1.0 e-5, 1.0 e-6, 1.0 e-7, 1.0 e-8};
  const double point = digits > 8 ? 1.0 e-8 : Points[digits];

  return((long)((Value > 0) ? Value / point + HALF_PLUS : Value / point - HALF_PLUS) * point);
}
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   double new_value = MyNormalizeDouble(d_value, 0);
   new_value = NormalizeDouble(d_value, 0);
   new_value = MyNormalizeDouble(d_value, 1);
   new_value = NormalizeDouble(d_value, 1);
   new_value = MyNormalizeDouble(d_value, 2);
   new_value = NormalizeDouble(d_value, 2);
   new_value = MyNormalizeDouble(d_value, 3);
   new_value = NormalizeDouble(d_value, 3);
   new_value = MyNormalizeDouble(d_value, 4);
   new_value = NormalizeDouble(d_value, 4);
   new_value = MyNormalizeDouble(d_value, 5);
   new_value = NormalizeDouble(d_value, 5);
   new_value = MyNormalizeDouble(d_value, 6);
   new_value = NormalizeDouble(d_value, 6);
   new_value = MyNormalizeDouble(d_value, 7);
   new_value = NormalizeDouble(d_value, 7);
   new_value = MyNormalizeDouble(d_value, 8);
   new_value = NormalizeDouble(d_value, 8);
   new_value = MyNormalizeDouble(d_value, 9);
   new_value = NormalizeDouble(d_value, 9);
   if (new_value ==0.0)
   {}  
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const int begin,
                const double &price[])
  {
//---
   
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
 
prostotrader:

Voici votre code, testez-le.

void OnStart( void )
{
  double Val = 12345.012345;
  
  double Val2 = Val / 1.0 e-5;
  Val2 += HALF_PLUS; // Val2 == 1234501235.0
  
  long Val3 = (long)Val2; // Val3 == 1234501234
    
  return;
};

Val2 - correct. Val3 après conversion en long - pas correct. Apparemment, il s'agit d'une particularité de la double représentation des nombres à virgule flottante. Nous devons incrémenter EPSILON. Je n'arrive pas à comprendre dans ma tête endormie. Peut-être que des personnes bien informées pourront me donner un indice.

J'ai besoin de savoir quelles considérations les développeurs ont utilisé pour écrire ça.

//+------------------------------------------------------------------+
//| Сравнивает два значения типа double.                             |
//| RESULT                                                           |
//|   Возвращает истину, если значения равны и                       |
//|   ложь в противном случе.                                        |
//+------------------------------------------------------------------+
bool CEnvironment::DoubleEquals(const double a,const double b)
  {
//---
   return(fabs(a-b)<=16*DBL_EPSILON*fmax(fabs(a),fabs(b)));
//---
  }

Il semble que ce soit là que le chien soit enterré.

 
Maintenant, il fonctionne toujours correctement, mais seulement 10 % plus vite que l'original.
double MyNormalizeDouble( const double Value, const uint digits )
{
  static const double Points[] = {1.0 e-0, 1.0 e-1, 1.0 e-2, 1.0 e-3, 1.0 e-4, 1.0 e-5, 1.0 e-6, 1.0 e-7, 1.0 e-8};
  const double point = digits > 8 ? 1.0 e-8 : Points[digits];
  const long Integer = (long)Value; // чтобы не создавать крайне медленный относительный epsilon

  return((long)((Value > 0) ? (Value - Integer) / point + HALF_PLUS : (Value - Integer) / point - HALF_PLUS) * point + Integer);
}
prostotrader, Merci d'avoir trouvé les divergences !
 
fxsaber:

Il semble que ce soit là que le chien soit enterré.

Les racines poussent à partir du forum RSDN

DBL_EPSILON définit une différence de 1 (un !) bit significatif d'un exposant lorsqu'il est appliqué au nombre 1,0. En pratique, cette différence n'existe pas : les nombres sont soit strictement égaux, soit peuvent différer de plus d'un bit significatif. Par conséquent, vous devez prendre quelque chose comme 16*DBL_EPSILON pour ignorer la différence de 4 bits les moins significatifs (ou environ un chiffre décimal et demi le moins significatif sur environ 16 disponibles).

Bien sûr, il existe des cas où la gamme de chiffres est plus ou moins connue et prévisible. Disons, 0...1000. Dans ce cas, vous pouvez prendre une constante comme 1000*16*DBL_EPSILON pour une comparaison approximative. Mais nous devons garder à l'esprit qu'une telle comparaison transforme toute l'idée de virgule flottante en virgule fixe (devinez pourquoi).

 

Une variante de CopyTicks, qui est parfois plus rapide de plusieurs ordres de grandeur que l'original (de > 0)

int MyCopyTicks( const string Symb, MqlTick& Ticks[], const uint flags = COPY_TICKS_ALL, const ulong from = 0, const uint count = 0 )
{
  int Res = (from == 0) ? CopyTicks(Symb, Ticks, flags, 0, count) : -1;
  
  if (from > 0)
  {    
    uint count2 = 1;
    
    MqlTick NewTicks[];    
    int Amount = CopyTicks(Symb, NewTicks, flags, 0, count2);
    
    while ((Amount > 0) && ((ulong)NewTicks[0].time_msc >= from))
    {
      count2 <<= 1;
      
      Amount = CopyTicks(Symb, NewTicks, flags, 0, count2);
    }

    for (int i = 1; i < Amount; i++)
      if ((ulong)NewTicks[i].time_msc >= from)
      {
        Res = ArrayCopy(Ticks, NewTicks, 0, i, (count == 0) ? 2000 : count);
        
        break;
      }    
  }
  
  return(Res);
}
Raison: