Kann Preis != Preis ?

 

Ich versuche, etwas Seltsames zu verstehen, das ich gerade sehe, damit ich es in Zukunft besser codieren kann.

Mir ist aufgefallen, dass mit einem meiner Indikatoren etwas Seltsames passiert. Er tat nicht das, was er hätte tun sollen, also habe ich den Code überprüft und er sah korrekt aus. Also habe ich ein wenig nachgeforscht und schließlich einen kleinen Testindikator erstellt.

Im Wesentlichen scheint dies zuzutreffen...

double TestValue = iClose(NULL, 0, 0);
   
if(TestValue != NormalizeDouble(TestValue, Digits) )

Haben Sie eine Idee, wie das passiert?

 
Zuvor gefragt und beantwortet
 
RaptorUK:

. . haben Sie eine Idee, wie das passiert?

Es liegt an der internen Funktionsweise von NormalizeDouble(). Zum Beispiel...

   double TestValue = 1.57373;
   if (TestValue != NormalizeDouble(TestValue, 5)) MessageBox("WTF?");

Das gleiche Ergebnis erhalten Sie übrigens auch, wenn Sie folgendes tun:

   double TestValue = StrToDouble("1.57373");
   if (TestValue != NormalizeDouble(TestValue, 5)) MessageBox("WTF?");

Nach der ersten Zuweisung ist TestValue = 1.5737300000000001. NormalizeDouble(..., 5) ergibt daraufhin 1.57372999999999.

 
WHRoeder:
Zuvor gefragt und beantwortet
Bei allem Respekt, ich glaube nicht, dass dieser Beitrag mein Problem in diesem Thread beantwortet.
Ich weiß, dass es andere Möglichkeiten gibt, als NormalizeDouble ... was ich nicht verstehe, ist, warum iClose einen Wert zurückgibt, der nicht bereits normalisiert ist ...
 
jjc:

Es liegt an der internen Funktionsweise von NormalizeDouble(). Zum Beispiel...

Das gleiche Ergebnis erhalten Sie übrigens auch, wenn Sie folgendes tun:

Nach der anfänglichen Zuweisung ist TestValue = 1.5737300000000001. NormalizeDouble(..., 5) ergibt daraufhin 1,57372999999999.


Wie erreiche ich also, dass TestValue gleich 1,57373 und nicht > oder < ist?
 
RaptorUK:

Wie kann ich also erreichen, dass TestValue gleich 1,57373 und nicht > oder < ist?
Falls dies noch nicht klar ist: 1,57373 kann nicht exakt als Fließkommawert dargestellt werden. Das Gleiche gilt für Werte wie 0,1. Die einzige Merkwürdigkeit ist, dass NormalizeDouble() am Ende eine andere Annäherung verwendet als andere Teile der MQ4-Sprache.
 
jjc:
Falls dies noch nicht klar ist: 1,57373 kann nicht exakt als Fließkommawert dargestellt werden. Das Gleiche gilt für Werte wie 0,1. Die einzige Merkwürdigkeit ist, dass NormalizeDouble() am Ende eine andere Annäherung verwendet als andere Teile der MQ4-Sprache.

Ah ... nein, das war mir nicht klar ... das wusste ich nicht. Danke, ich werde das überprüfen.
 
RaptorUK:
Ah ... nein, das war mir nicht klar ... das wusste ich nicht. Danke, ich werde es nachprüfen.

Fließkommawerte und -arithmetik sind schnell, weil der Prozessor des Computers sie unterstützt, allerdings mit dem Nachteil, dass einige Werte nicht präzise in einer Fließkommavariablen dargestellt werden können. (Ein Beispiel für die Auswirkungen auf die Geschwindigkeit finden Sie unter https://www.mql5.com/en/forum/116228/page2#156859).

In der Tat kann alles, was mit Doppelwerten zu tun hat, eine Art Rundungsfehler verursachen. Dies führt zu allen möglichen lustigen Macken. Zum Beispiel 0,1 * 10 = 1,0, aber 0,1 + 0,1 + 0,1 + 0,1 + 0,1 + 0,1 + 0,1 + 0,1 + 0,1 + 0,1 != 1,0

Daraus ergibt sich, dass NormalizeDouble(x, y) nicht genau gleichbedeutend mit Round(x, y) ist. NormalizeDouble() gibt die nächstmögliche Fließkomma-Näherung an den gerundeten Wert zurück. Wenn Sie NormalizeDouble(a, n) == NormalizeDouble(b, n) verwenden, sagen Sie im Grunde: "Sind a und b gleich, unter Berücksichtigung der Tatsache, dass die Fließkommaarithmetik Rundungsdifferenzen an mehr als n Dezimalstellen einführen kann?".

Wie schon viele gesagt haben, ist NormalizeDouble(a, 5) == NormalizeDouble(b, 5) daher im Grunde gleichbedeutend mit MathAbs(a - b) < 0,00001, wobei letzteres etwas schneller ausgeführt wird. Letzteres ist auch deshalb üblich, weil es in Sprachen/Plattformen weit verbreitet ist, die keine praktische Entsprechung zur Funktion NormalizeDouble() bieten. Der Leistungsunterschied ist jedoch so gering, dass ich bei NormalizeDouble() bleiben würde, wenn Sie das Gefühl haben, dass Ihr Code dadurch besser lesbar wird.

All dies ist völlig normal für Sprachen, die einen Double-Datentyp haben. Der Teil, der einige proprietäre und typische MQ4-Schrulligkeiten einführt, ist, dass 1.57373 != NormalizeDouble(1.57373, 5). Es ist pervers, dass die Deklaration der Konstante 1.57373 und die Verwendung von NormalizeDouble() unterschiedliche Best-Case-Gleitkomma-Approximationen des Wertes wählen.

 

Vielen Dank :-)

Ich war mir des Problems bewusst, aber nicht ganz über den Grund und somit auch nicht über die möglichen Auswirkungen.

 
außer bei Null niemals Doppelgänger auf Gleichheit vergleichen
if (a > b)
if (a - b > Point / 2.)
if (a >= b)
if (a - b > -Point)
if (a != b)
if (MathAbs(a - b) > Point / 2.)
 
WHRoeder:
außer mit Null niemals Doubles auf Gleichheit vergleichen


Ich habe etwas mehr als hundert Codezeilen, in denen ich genau das tue ... und ich habe NormalizeDouble für fast alles in Sichtweite verwendet, damit es zuverlässig funktioniert. Ich verstehe die Idee hinter Ihren Vorschlägen, vielen Dank, aber ich denke, dass sie sich negativ auf die Lesbarkeit meines Codes und damit auf die Leichtigkeit zukünftiger Änderungen auswirken könnten.

Ich werde diesen Codeblock in nicht allzu ferner Zukunft ändern, damit er auch mit anderen Zeitrahmen als dem Zeitrahmen des Diagramms funktioniert, auf dem er läuft. Wenn ich dazu komme, plane ich, die NormalizeDoubles zu beseitigen und durch etwas anderes zu ersetzen ... ich bin mir noch nicht 100%ig sicher, vielleicht eine Konvertierung in Ganzzahlen vor dem Vergleich ...

Danke für die Hilfe, wie immer :-)

Grund der Beschwerde: