Fehler, Irrtümer, Fragen - Seite 2822

 
Nikolai Semko:

Nur die Rundung erfolgt nicht mit den Standardfunktionen round(), ceil() und floor(), da diese ebenfalls double zurückgeben.

Aber durch diese, vor allem sie arbeiten schneller als die regulären:

Es mag schneller sein, aber es ist einfach falsch.
Geben Sie etwas wie 12345.0000000000001 in Ihre Ceil ein (ähnlich wie in Ihrem Beispiel), und Sie können 12346 in der Ausgabe erhalten
 
Alexey Navoykov:
Es mag schneller sein, aber es ist einfach falsch.
Geben Sie etwas wie 12345.0000000000001 (ähnlich wie in Ihrem Beispiel) in Ihre Ceil ein, und Sie können 12346 in der Ausgabe erhalten.

Haben Sie es selbst ausprobiert?
Versuchen Sie es:

Print(ceil( 12345.0000000000001));
Print(Ceil( 12345.0000000000001));
Print(ceil( 12345.000000000001));
Print(Ceil( 12345.000000000001));

Ausgabe:

2020.08.10 12:03:23.856 ErrorNormalizeDouble (EURUSD,M1)        12345.0
2020.08.10 12:03:23.856 ErrorNormalizeDouble (EURUSD,M1)        12345
2020.08.10 12:03:23.856 ErrorNormalizeDouble (EURUSD,M1)        12346.0
2020.08.10 12:03:23.856 ErrorNormalizeDouble (EURUSD,M1)        12346
sollte 12346 sein, da es sich um eine Ceil handelt ("Gibt den nächsten ganzzahligen numerischen Wert von oben zurück.")
der erste Fall ist 12345, da die signifikanten Ziffern im Double-Typ 17 sind, während Sie 18 haben
 
Nikolai Semko:

Wirklich, man kann keine Doppelgänger vergleichen. Das ist einfach eine harte Regel.

Natürlich ist es möglich und manchmal sogar notwendig, Doppelgänger direkt miteinander zu vergleichen.

Zum Beispiel wird OnTick während der Optimierung manchmal eine Trillion Mal aufgerufen. Um festzustellen, ob ein schwebendes Limit ausgeführt werden soll oder nicht, vergleicht der integrierte Tester den aktuellen Preis des entsprechenden Symbols mit dem Limitpreis. Er tut dies für jeden schwebenden Auftrag vor jedem OnTick-Aufruf. D.h. diese Kontrollen werden zig- und hundertmilliardenfach durchgeführt.

Und das geschieht jedes Mal durch Normalisierung. Nun, das ist eine schreckliche Verschwendung von Computerressourcen. Da die Preise der ausstehenden Aufträge und das Symbol vorläufig normalisiert sind. Daher können und sollten sie direkt miteinander verglichen werden.

Der benutzerdefinierte MQL-Tester übertrifft den eingebauten MQL-Tester bei der Leistung leicht.

 

fxsaber
:

Natürlich ist es möglich und manchmal sogar notwendig, Doppelgänger direkt miteinander zu vergleichen.

Zum Beispiel wird Optimize OnTick manchmal eine Trillion Mal aufgerufen. Um festzustellen, ob ein schwebendes Limit ausgeführt werden soll oder nicht, vergleicht der integrierte Tester den aktuellen Preis des entsprechenden Symbols mit dem Limitpreis. Er tut dies für jeden schwebenden Auftrag vor jedem OnTick-Aufruf. D.h. diese Kontrollen werden zig- und hundertmilliardenfach durchgeführt.

Und das geschieht jedes Mal durch Normalisierung. Nun, das ist eine schreckliche Verschwendung von Computerressourcen. Da die Preise der ausstehenden Aufträge und das Symbol vorläufig normalisiert sind. Daher können und sollten sie direkt miteinander verglichen werden.

Der benutzerdefinierte MQL-Tester übertrifft den eingebauten MQL-Tester bei der Leistung leicht.

NormalizeDouble() ist eine sehr teure Funktion. Deshalb sollten Sie es besser vergessen.

Hier ist ein Skript, das den Unterschied zwischen NormalizeDouble() und normalize with int demonstriert:

#define   SIZE 1000000

int Ceil (double x) {return (x-(int)x>0)?(int)x+1:(int)x;}
int Round(double x) {return (x>0)?(int)(x+0.5):(int)(x-0.5);}
int Floor(double x) {return (x>0)?(int)x:((int)x-x>0)?(int)x-1:(int)x;}
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   double a[SIZE];
   double s1=0,s2=0, s3=0;
   for (int i=0;i<SIZE;i++)  a[i]=(rand()-16384)/M_PI;
   
   ulong t1=GetMicrosecondCount();
   for (int i=0;i<SIZE;i++) s1+=a[i];
   t1=GetMicrosecondCount()-t1;  
   
   ulong t2=GetMicrosecondCount();
   for (int i=0;i<SIZE;i++) s2+=NormalizeDouble(a[i],5);
   t2=GetMicrosecondCount()-t2; 
   
   ulong t3=GetMicrosecondCount();
   for (int i=0;i<SIZE;i++) s3+=Round(a[i]*100000);
   s3/=100000;
   t3=GetMicrosecondCount()-t3; 
   
   Print("простая сумма                            - " + string(t1)+ " микросекунд, сумма = "+ DoubleToString(s1,18));
   Print("сумма с NormalizeDouble                  - " + string(t2)+ " микросекунд, сумма = "+ DoubleToString(s2,18));
   Print("сумма, нормализированная через int       - " + string(t3)+ " микросекунд, сумма = "+ DoubleToString(s3,18));
  }

Ergebnis:

2020.08.10 12:55:30.766 TestSpeedNormalizeDouble (USDCAD,H4)    простая сумма                            - 1394 микросекунд, сумма = 626010.5038610587362201
2020.08.10 12:55:30.766 TestSpeedNormalizeDouble (USDCAD,H4)    сумма с NormalizeDouble                  - 5363 микросекунд, сумма = 626010.5046099 795727060
2020.08.10 12:55:30.766 TestSpeedNormalizeDouble (USDCAD,H4)    сумма, нормализированная через int       - 1733 микросекунд, сумма = 626010.5046099999 453873
SZZ die Normalisierung durch int ist auch genauer (Sie können es durch die Anzahl der Neunen nach der letzten Ziffer der Normalisierung - blau hervorgehoben - sehen).
 
Nikolai Semko:

NormalizeDouble() ist eine sehr teure Funktion. Deshalb ist es besser, es zu vergessen.

Hier ist ein Skript, das den Unterschied zwischen NormalizeDouble() und normalize with int demonstriert:

Ergebnis:

Bei SZZ ist die Normalisierung nach int sogar noch genauer (zu erkennen an der Anzahl der Neunen nach der letzten Ziffer der Normalisierung - blau hervorgehoben).

und wenn die Summierung nicht über double, sondern über long erfolgt, dann ist das Ergebnis noch beeindruckender, da die Summierung über int (Multiplikation und Rundung, gefolgt von der Division der Endsumme) schneller berechnet wird als die normale Summe von double.

#define   SIZE 1000000

int Ceil (double x) {return (x-(int)x>0)?(int)x+1:(int)x;}
int Round(double x) {return (x>0)?(int)(x+0.5):(int)(x-0.5);}
int Floor(double x) {return (x>0)?(int)x:((int)x-x>0)?(int)x-1:(int)x;}
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   double a[SIZE];
   double s1=0,s2=0, s3=0;
   long s=0;
   for (int i=0;i<SIZE;i++)  a[i]=(rand()-16384)/M_PI;
   
   ulong t1=GetMicrosecondCount();
   for (int i=0;i<SIZE;i++) s1+=a[i];
   t1=GetMicrosecondCount()-t1;  
   
   ulong t2=GetMicrosecondCount();
   for (int i=0;i<SIZE;i++) s2+=NormalizeDouble(a[i],5);
   t2=GetMicrosecondCount()-t2; 
   
   ulong t3=GetMicrosecondCount();
   for (int i=0;i<SIZE;i++) s+=Round(a[i]*100000);
   s3=s/100000.0;
   t3=GetMicrosecondCount()-t3; 
   
   Print("простая сумма                            - " + string(t1)+ " микросекунд, сумма = "+ DoubleToString(s1,18));
   Print("сумма с NormalizeDouble                  - " + string(t2)+ " микросекунд, сумма = "+ DoubleToString(s2,18));
   Print("сумма, нормализированная через int       - " + string(t3)+ " микросекунд, сумма = "+ DoubleToString(s3,18));  
  }

Ergebnis:

2020.08.10 13:15:58.982 TestSpeedNormalizeDouble (USDCAD,H4)    простая сумма                            - 1408 микросекунд, сумма = 460384.3207830497995019
2020.08.10 13:15:58.982 TestSpeedNormalizeDouble (USDCAD,H4)    сумма с NormalizeDouble                  - 6277 микросекунд, сумма = 460384.3162300114054233
2020.08.10 13:15:58.982 TestSpeedNormalizeDouble (USDCAD,H4)    сумма, нормализированная через int       - 964 микросекунд,  сумма = 460384.3162299999967218
 
Nikolai Semko:

Und wenn die Summierung nicht über double, sondern über long erfolgt, dann ist das Ergebnis noch beeindruckender, denn die Summierung über int (Multiplikation und Rundung, gefolgt von der Division der Gesamtsumme) ist schneller als eine normale Double-Summe.

Ergebnis:

Dezimal für Vergleich addieren.

Falscher Link, es handelt sich nicht um eine vollständige Implementierung.

 
fxsaber:

Und das geschieht jedes Mal durch Normalisierung. Das ist eine schreckliche Verschwendung von Computerressourcen.

Denn auch wenn die Preise nicht normalisiert sind, wird die Prüfung einfach ohne jegliche Normalisierung durchgeführt:

 if (fabs(price-limitprice) < ticksize/2)

Da die Preise ein Vielfaches der Zeckengröße sind

 
Nikolai Semko:
Außerdem erweist sich die Normalisierung durch int als genauer (zu erkennen an der Anzahl der Neunen nach der letzten Ziffer der Normalisierung - blau hervorgehoben).

Der Test ist falsch. Warum teilen Sie nur einmal am Ende durch 100000.0? Das sollte bei jeder Iteration durchgeführt und dann summiert werden. Das ist ein fairer Vergleich. Aber das ist überhaupt keine Normalisierung - Sie haben nur Ihren Testalgorithmus optimiert. Natürlich wird es schneller und genauer sein (weil der kumulierte Fehler reduziert wird).

 
Alexey Navoykov:

Woher wissen Sie das?

Denn Sie können nicht-normierte Preise in den Tester eingeben, und er wird sie identisch behandeln.

Denn selbst wenn die Preise nicht normalisiert sind, ist die Prüfung auch ohne Normalisierung leicht möglich.

Mit Normalisierung meinte ich in diesem Fall einen einzigen Standardalgorithmus, nach dessen Anwendung man Doppelwerte dieses Standards direkt vergleichen kann.

Der Prüfer vergleicht also keine Doppelgänger direkt. Dies geschieht durch NormalizeDouble, ticksize oder etwas anderes. Aber sicher nicht durch den direkten Vergleich von Doppelgängern. Und das ist ganz und gar nicht rational.

 
fxsaber:

Natürlich ist es möglich und manchmal sogar notwendig, Doppelgänger direkt miteinander zu vergleichen.

Zum Beispiel wird OnTick während Optimize manchmal eine Billion Mal aufgerufen. Um zu verstehen, ob ein hängendes Limit ausgeführt werden soll oder nicht, vergleicht der eingebaute Tester den aktuellen Preis des entsprechenden Symbols mit dem Limitpreis. Er tut dies für jeden schwebenden Auftrag vor jedem OnTick-Aufruf. D.h. diese Kontrollen werden zig- und hundertmilliardenfach durchgeführt.

Und das geschieht jedes Mal durch Normalisierung. Nun, das ist eine schreckliche Verschwendung von Computerressourcen. Da die Preise der ausstehenden Aufträge und das Symbol vorläufig normalisiert sind. Daher können und sollten sie direkt miteinander verglichen werden.

Der benutzerdefinierte MQL-Tester übertrifft den eingebauten MQL-Tester in der Leistung nicht.

Also beschloss ich, die leistungsfeindliche Version zu überprüfen.
Und das Ergebnis war überraschend.
Der Vergleich selbst von vornormierten Double ist im Durchschnitt sogar langsamer, als wenn Double durch Epsilon oder Umwandlung in int verglichen wird.

#define  SIZE 1000000

int Ceil (double x) {return (x-(int)x>0)?(int)x+1:(int)x;}
int Round(double x) {return (x>0)?(int)(x+0.5):(int)(x-0.5);}
int Floor(double x) {return (x>0)?(int)x:((int)x-x>0)?(int)x-1:(int)x;}

bool is_equal(double d1, double d2, double e=0.000000001) {return fabs(d1-d2)<e;}

void OnStart()
  {
   double a[SIZE], a_norm[SIZE];
   int s1=0,s2=0, s3=0;
   for (int i=0;i<SIZE;i++)  {
     a[i]=(rand()-16384)/1641.1452;
     a_norm[i]=NormalizeDouble(a[i],2);
   }
   double test = 1.11;
   
   ulong t1=GetMicrosecondCount();
   for (int i=0;i<SIZE;i++) if (a_norm[i]==test) s1++;
   t1=GetMicrosecondCount()-t1;  
   
   ulong t2=GetMicrosecondCount();
   for (int i=0;i<SIZE;i++) if (is_equal(a[i],test,0.005)) s2++;
   t2=GetMicrosecondCount()-t2; 
   
   ulong t3=GetMicrosecondCount();
   int test_int = test*100;
   for (int i=0;i<SIZE;i++) if (Round(a[i]*100)==test_int) s3++;
   t3=GetMicrosecondCount()-t3; 
   
   
   Print("простое сравнение предварительно нормализированых double - " + string(t1)+ " микросекунд, всего совпадений = "+ string(s1));
   Print("сравнение double через эпсилон                           - " + string(t2)+ " микросекунд, всего совпадений = "+ string(s2));
   Print("сравнение double через преобразование в int              - " + string(t3)+ " микросекунд, всего совпадений = "+ string(s3));  
  }

Das Ergebnis:

2020.08.10 14:31:39.620 TestCompareDouble (USDCAD,H4)   простое сравнение предварительно нормализированых double - 900  микросекунд, всего совпадений = 486
2020.08.10 14:31:39.620 TestCompareDouble (USDCAD,H4)   сравнение double через эпсилон                           - 723  микросекунд, всего совпадений = 486
2020.08.10 14:31:39.620 TestCompareDouble (USDCAD,H4)   сравнение double через преобразование в int              - 805  микросекунд, всего совпадений = 486
2020.08.10 14:31:42.607 TestCompareDouble (USDCAD,H4)   простое сравнение предварительно нормализированых double - 1533 микросекунд, всего совпадений = 488
2020.08.10 14:31:42.607 TestCompareDouble (USDCAD,H4)   сравнение double через эпсилон                           - 758  микросекунд, всего совпадений = 488
2020.08.10 14:31:42.607 TestCompareDouble (USDCAD,H4)   сравнение double через преобразование в int              - 790  микросекунд, всего совпадений = 488
2020.08.10 14:31:44.638 TestCompareDouble (USDCAD,H4)   простое сравнение предварительно нормализированых double - 986  микросекунд, всего совпадений = 472
2020.08.10 14:31:44.638 TestCompareDouble (USDCAD,H4)   сравнение double через эпсилон                           - 722  микросекунд, всего совпадений = 472
2020.08.10 14:31:44.638 TestCompareDouble (USDCAD,H4)   сравнение double через преобразование в int              - 834  микросекунд, всего совпадений = 472

Ich schließe nicht aus, dass viel von der Neuheit und der Architektur des Prozessors abhängt, und für jemanden kann das Ergebnis anders sein.

Um die Wahrheit zu sagen - ich verstehe nicht einmal, warum das passiert.
Es scheint, dass der Compiler nichts mit der Summe der Zufallszahlen zu optimieren hat. Sie können keine Rundungen außerhalb von Klammern setzen.
Es scheint, dass der Double-Vergleich im Prozessor ein Befehl ist
Beim Vergleich durch Epsilon (der schnellste Weg) haben wir immer noch eine Vergleichsoperation von zwei Doubles, aber zusätzlich haben wir einen Funktionsaufruf mit Übergabe von drei Parametern und eine Subtraktionsoperation.
Hängt die Leistung der Operation des Vergleichs zweier Doppelgänger von den Werten der Variablen selbst ab? Das bezweifle ich.
Meine Güte, ich verstehe das nicht. Bitte helfen Sie mir, was habe ich nicht beachtet oder wo habe ich einen Fehler gemacht?