Alternative Implementierungen von Standardfunktionen/-ansätzen - Seite 3

 
fxsaber:
Es stellt sich heraus, dass #import ex5 das Übel der Optimierung ist.

In Bezug auf die Möglichkeit einer globalen Optimierung, ja.

Wir haben ziemlich aggressives Inlining, ohne zu versuchen, den Code kleiner zu machen. Im globalen Optimierungsmodus erzeugen wir also sehr guten Code.

Dies zeigt sich in der Kompilierzeit, wo wir die resultierende Geschwindigkeit an die Spitze der Liste setzen.

 
prostotrader:

fxsaber

Es gibt einen Fehler in Ihrem Code

Danke, ich habe es korrigiert.
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:
Danke, korrigiert.

Trotzdem ein Fehler.

Es sollte eine 5 am Ende sein.

 
prostotrader:

Immer noch ein Fehler

Es handelt sich nicht um einen Fehler, sondern um eine Rundung. Das ist genau das, was die Standardversion tut.
 
fxsaber:
Dies ist kein Fehler, sondern eine Rundung. So wird es in der Standardversion gehandhabt.
Ich habe einen Fehler mit dem falschen Screenshot gemacht, schauen Sie noch einmal (Bild ersetzen)
 

Hier ist der Code, den Sie testen können

//+------------------------------------------------------------------+
//|                                                         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:

Hier ist Ihr Code, testen Sie ihn.

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 - richtig. Val3 nach Umwandlung in Long - nicht korrekt. Offenbar handelt es sich um eine Besonderheit der doppelten Darstellung von Gleitkommazahlen. Wir müssen EPSILON aufstocken. Ich kann es mit meinem müden Kopf nicht erkennen. Vielleicht können mir einige sachkundige Personen einen Tipp geben.

Ich muss herausfinden, welche Überlegungen die Entwickler angestellt haben, um dies zu schreiben

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

Das scheint der Ort zu sein, an dem der Hund begraben ist.

 
Jetzt funktioniert es immer korrekt, aber nur 10% schneller als das 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, danke für das Auffinden der Unstimmigkeiten!
 
fxsaber:

Das scheint der Ort zu sein, an dem der Hund begraben ist.

Die Wurzeln wachsen aus dem RSDN-Forum

DBL_EPSILON definiert eine Differenz von 1 (einem!) signifikanten Bit eines Exponenten bei Anwendung auf die Zahl 1,0. In der Praxis gibt es keinen solchen Unterschied - die Zahlen sind entweder absolut gleich oder können sich um mehr als ein signifikantes Bit unterscheiden. Daher muss man etwa 16*DBL_EPSILON nehmen, um die Differenz von 4 niederwertigen Bits zu ignorieren (oder etwa anderthalb letzte signifikante Dezimalziffern von etwa 16 verfügbaren).

Natürlich gibt es Fälle, in denen die Zahlenspanne mehr oder weniger bekannt und vorhersehbar ist. Sagen wir, 0...1000. In diesem Fall können Sie für einen groben Vergleich eine Konstante wie 1000*16*DBL_EPSILON verwenden. Wir müssen jedoch bedenken, dass ein solcher Vergleich die gesamte Gleitkomma-Idee in eine Festkomma-Idee verwandelt (raten Sie mal, warum).

 

Eine Variante von CopyTicks, die manchmal um mehrere Größenordnungen schneller ist als das Original (ab > 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);
}
Grund der Beschwerde: