Versuchen Sie, die Einschränkung zu entfernen
Note: Only one arithmetic operator can be used per statement.
Und versuchen Sie, Vergleichsoperatoren "statisch" zu machen.
Versuchen Sie, die Einschränkung zu entfernen
Und versuchen Sie, Vergleichsoperatoren "statisch" zu machen.
Operatoren können nicht als "statisch" deklariert werden.
Es kann mehr als eine (überladene) arithmetische Operation pro Anweisung geben, vorausgesetzt, dass jeder Satz von zwei Operanden in der richtigen Reihenfolge in Klammern eingeschlossen ist. Ich empfehle dies trotzdem nicht.
CDouble foo = 3, bar = 4, spam = 3; CDouble error = foo+bar+spam; //ERRORCDouble error_too = (pi2 + pi5)+pi2; //ERROR
CDouble correct = foo+(bar+spam);// OK!
Um mögliche Unklarheiten zu beseitigen, ist die korrekte Art und Weise, die Arithmetik für Anweisungen mit mehr als einem Operator zu behandeln, nicht die überladenen Operatoren zu verwenden, sondern stattdessen eine der anwendbaren value get-Methoden.
CDouble sum, foo=3, bar=2, spam=1; sum = foo.AsRawDouble() + bar.AsRounded() + spam.AsRoundedTick(); Print(sum.ToString()); //6
Operatoren können nicht als "statisch" deklariert werden.
Es kann mehr als eine arithmetische Operation (Überladung) pro Anweisung geben, vorausgesetzt, dass jeder Satz von zwei Operanden in der richtigen Reihenfolge in Klammern eingeschlossen wird. Ich empfehle dies trotzdem nicht.
class CDouble2 : public CDouble { private: static CDouble2 TmpDouble; public: const CDouble2* const operator +( const double Value ) const { CDouble2::TmpDouble = this.m_value + Value; return(&CDouble2::TmpDouble); } const CDouble2* const operator +( const CDouble2 &Other ) const { return(this + Other.m_value); } static CDouble2* const Compare2( const double Value ) { CDouble2::TmpDouble = Value; return(&CDouble2::TmpDouble); } static CDouble2* const Compare2( const CDouble2 &Other ) { CDouble2::TmpDouble = Other; return(&CDouble2::TmpDouble); } }; static CDouble2 CDouble2::TmpDouble; #define _CP(A) CDouble2::Compare2(A) #define PRINT(A) Print(#A + " = " + (string)(A)); void OnStart() { CDouble2 foo = 3, bar = 4, spam = 3; CDouble2 error = foo+bar+spam + foo+bar+spam; //OK! PRINT(error.ToString()); // 10 PRINT(_CP(foo + error + 5) > 2); PRINT(_CP(25) > foo + bar + 7 +spam); PRINT((foo + bar + spam + 9).ToString()); PRINT((_CP(9) + foo).ToString()); PRINT(foo + 7 > 11) }
Ergebnis
error.ToString() = 20 _CP(foo+error+5)>2 = true _CP(25)>foo+bar+7+spam = false (foo+bar+spam+9).ToString() = 19 (_CP(9)+foo).ToString() = 12 foo+7>11 = false
Ergebnis
Das ist sehr clever und gefällt mir sehr gut, aber es ist zu clever für die meisten Benutzer... (das wurde uns beiden in den Foren schon vorgeworfen ;) Ich werde Ihre Änderungen in meine persönliche Bibliothek übernehmen, und andere können das auch, aber zum Nutzen einer größeren Zahl von Benutzern werde ich es einfach halten und bei der offiziellen Empfehlung bleiben, eine der Getter-Methoden aufzurufen. ( z.B. num1.AsRounded() * num2.AsRounded() + num3.AsRounded() )
FWIW Ich persönlich mag (num1*num2+num3).AsRounded()
Herausforderungen mit CDouble2 wie vorgeschlagen:
void Func(double param) { } void OnStart() { CDouble2 foo = 2, bar = 3; double number = foo+bar; //ERROR Func(foo+bar); //ERROR }
* Version 1.01:
- Fehler behoben, bei dem arithmetische Operatoren keine gerundeten Werte zurückgaben.
- Symbol Setter Methode hinzugefügt, um das Symbol zu setzen, nachdem der Konstruktor aufgerufen wurde.
Hallo, nicholishen. Ich habe deine Bibliothek für einige Zeit getestet. Sie ist großartig und macht das Runden von Preisen und Mengen zu einer einfachen Aufgabe.
Aber ich habe einige Bedenken bezüglich der Genauigkeit Ihrer Rundungsmethoden. Ich habe eine Menge Rundungsfehler in den Funktionen RoundToStep(), RoundToStepUp(), RoundToStepDown() und RoundToTick() gefunden. Diese Fehler treten immer bei Randzahlen auf, die auf 5 enden (wie 1.12345).
Zum Beispiel gibt CDouble::RoundToStep(1.700605, 0.00001) 1.70060 zurück, anstatt des korrekten Ergebnisses 1.70061
Die Gleichung round(number / point) * point sollte in round(number * power) / power korrigiert werden, wobei sowohl point als auch power von der Anzahl der Dezimalstellen abgeleitet sind, auf die gerundet werden soll.
Denn der Wert von 1 Punkt, der eigentlich 0,00001 sein sollte, ist als 64-Bit-Gleitkommazahl mit doppelter Genauigkeit tatsächlich als 0,0000100000000000000008180305391403130954586231382563710 kodiert. Dies führt dazu, dass das Endergebnis Ihrer Rundungsmethode, round(number / point) * point, sehr oft um 1 Punkt (0,00001) vom richtigen Ergebnis abweicht.
Um eine korrekte "arithmetische" Rundung durchzuführen (Midpoint Rounding away from zero), ist es außerdem eine gute Methode, ein halbes Epsilon als Korrektur zu addieren oder zu subtrahieren. (Dies gleicht die vom Prozessor vorgenommene Halb-zu-Gleich-Rundung aus, wie sie in den IEEE-754-Spezifikationen vorgeschrieben ist, insbesondere bei den Midpoint-Randfällen).
Die Funktion NormalizeDouble() von mql behandelt all diese Probleme korrekt, Sie sollten sie verwenden, um eine korrekte "arithmetische" Rundung durchzuführen.
Hier ist auch der Quellcode einer Funktion, die ich für die arithmetische Rundung geschrieben habe, Sie können sie selbst testen. Diese Funktion hat genau die gleichen Ergebnisse wie NormalizeDouble(). Meine Funktion läuft sogar schneller und unterstützt eine höhere Rundungsgenauigkeit. (MQLs NormalizeDouble() ist auf 8 Dezimalstellen beschränkt).
/** * MidpointRounding away from zero ('arithmetische' Rundung) * Verwendet ein Halb-Epsilon zur Korrektur. (Dies gleicht die IEEE-754 * Halb-zu-gerade-Rundung aus, die in den Randfällen angewendet wurde). */ double RoundCorrect(double num, int precision) { double c = 0.5 * DBL_EPSILON * num; // double p = MathPow(10, Genauigkeit); //slow double p = 1; while (precision--> 0) p *= 10; if (num < 0) p *= -1; return MathRound((num + c) * p) / p; }
Außerdem finden Sie hier ein Skript, das Sie verwenden können, um die Rundungsgenauigkeit in der CDouble-Bibliothek zu testen. Ich hoffe, es ist nützlich für Sie.
#property strict #define PRINT(A) Print(#A + " = ", (A)) #define forEach(element, array) for (int __i = 0, __max = ArraySize((array)); __i < __max && ((element) = array[__i]) == (element); __i++) #include "CDouble.mqh" //+------------------------------------------------------------------+ //|| //+------------------------------------------------------------------+ string DoubleToFixed(double number, int decimals = 55) { return StringFormat(StringFormat("%%#.%if", decimals), number); } //+------------------------------------------------------------------+ //|| //+------------------------------------------------------------------+ void OnStart() { // Test der Rundung einiger Randfälle double numbers_3[] = {1.005, 2.175, 5.015, 16.025}; double numbers_6[] = {1.011885, 1.113325, 1.143355, 1.700605}; double num; forEach (num, numbers_3) { Print("----------------------------------------------"); PRINT( num ); // 3 Funktionen vergleichen (auf 2 Stellen runden) PRINT( CDouble::RoundToStep(num, 0.01) ); PRINT( NormalizeDouble(num, 2) ); PRINT( RoundCorrect(num, 2) ); } forEach (num, numbers_6) { Print("----------------------------------------------"); PRINT( num ); // 3 Funktionen vergleichen (auf 5 Stellen runden) PRINT( CDouble::RoundToStep(num, 0.00001) ); PRINT( NormalizeDouble(num, 5) ); PRINT( RoundCorrect(num, 5) ); } // Die Ursache für Rundungsprobleme in der CDouble-Bibliothek Print("----------------------------------------------"); PRINT( DoubleToFixed(0.01, 55) ); // 0.0000100000000000000008180305391403130954586231382563710 PRINT( DoubleToFixed(0.00001, 55) ); // 0.0100000000000000002081668171172168513294309377670288086 // Vergleich von NormalizeDouble und RoundCorrect durch exakte Gleichheit Print("----------------------------------------------"); PRINT( NormalizeDouble(numbers_6[0], 5) == RoundCorrect(numbers_6[0], 5) ); // wahr PRINT( NormalizeDouble(numbers_6[0], 4) == RoundCorrect(numbers_6[0], 4) ); // wahr PRINT( NormalizeDouble(numbers_6[0], 3) == RoundCorrect(numbers_6[0], 3) ); // wahr PRINT( NormalizeDouble(numbers_6[0], 2) == RoundCorrect(numbers_6[0], 2) ); // wahr PRINT( NormalizeDouble(numbers_6[0], 1) == RoundCorrect(numbers_6[0], 1) ); // wahr }
Hallo, nicholishen. Ich habe deine Bibliothek für einige Zeit getestet. Sie ist toll und macht das Runden von Preisen und Losen zu einer einfachen Aufgabe.
Aber ich habe einige Bedenken bezüglich der Genauigkeit Ihrer Rundungsmethoden. Ich habe eine Menge Rundungsfehler in den Funktionen RoundToStep(), RoundToStepUp(), RoundToStepDown() und RoundToTick() gefunden. Diese Fehler treten immer bei Randzahlen auf, die auf 5 enden (wie 1.12345).
Zum Beispiel gibt CDouble::RoundToStep(1.700605, 0.00001) 1.70060 zurück, anstatt des korrekten Ergebnisses 1.70061
Die Gleichung round(number / point) * point sollte in round(number * power) / power korrigiert werden, wobei sowohl point als auch power von der Anzahl der Dezimalstellen abgeleitet sind, auf die gerundet werden soll.
Denn der Wert von 1 Punkt, der eigentlich 0,00001 sein sollte, ist als 64-Bit-Gleitkommazahl mit doppelter Genauigkeit tatsächlich als 0,0000100000000000000008180305391403130954586231382563710 kodiert. Dies führt dazu, dass das Endergebnis Ihrer Rundungsmethode, round(number / point) * point, sehr oft um 1 Punkt (0,00001) vom richtigen Ergebnis abweicht.
Um eine korrekte "arithmetische" Rundung durchzuführen (Midpoint Rounding away from zero), ist es außerdem eine gute Methode, ein halbes Epsilon als Korrektur zu addieren oder zu subtrahieren. (Dadurch wird eine vom Prozessor vorgenommene Halb-zu-Gerade-Rundung ausgeglichen, wie sie in den IEEE-754-Spezifikationen vorgeschrieben ist, insbesondere bei den Midpoint-Randfällen).
Die Funktion NormalizeDouble() von mql behandelt all diese Probleme korrekt, Sie sollten sie verwenden, um eine korrekte "arithmetische" Rundung durchzuführen.
Hier ist auch der Quellcode einer Funktion, die ich für die arithmetische Rundung geschrieben habe, Sie können sie selbst testen. Diese Funktion hat genau die gleichen Ergebnisse wie NormalizeDouble(). Meine Funktion läuft sogar schneller und unterstützt eine höhere Rundungsgenauigkeit. (MQLs NormalizeDouble() ist auf 8 Dezimalstellen beschränkt).
Vielen Dank für diesen Hinweis. Ich werde den Code aktualisieren, um NormalizeDouble anstelle von round zu verwenden.
step * NormalizeDouble(number_to_round / step, 0)
Hallo, nicholishen. Ich habe deine Bibliothek für einige Zeit getestet. Sie ist toll und macht das Runden von Preisen und Losen zu einer einfachen Aufgabe.
Aber ich habe einige Bedenken bezüglich der Genauigkeit Ihrer Rundungsmethoden. Ich habe eine Menge Rundungsfehler in den Funktionen RoundToStep(), RoundToStepUp(), RoundToStepDown() und RoundToTick() gefunden. Diese Fehler treten immer bei Randzahlen auf, die auf 5 enden (wie 1.12345).
Zum Beispiel gibt CDouble::RoundToStep(1.700605, 0.00001) 1.70060 zurück, statt des richtigen Ergebnisses 1.70061
Die Gleichung round(number / point) * point sollte in round(number * power) / power korrigiert werden, wobei sowohl point als auch power von der Anzahl der Dezimalstellen abgeleitet sind, auf die gerundet werden soll.
Denn der Wert von 1 Punkt, der eigentlich 0,00001 sein sollte, ist als 64-Bit-Gleitkommazahl mit doppelter Genauigkeit tatsächlich als 0,0000100000000000000008180305391403130954586231382563710 kodiert. Dies führt dazu, dass das Endergebnis Ihrer Rundungsmethode, round(number / point) * point, sehr oft um 1 Punkt (0,00001) vom richtigen Ergebnis abweicht.
- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.
CDouble & CDoubleVector:
Eine Bibliothek für gängige Rundungsmethoden in der MQL-Entwicklung, primitive Wrapper-Klasse für Typ (double) und Vektor für CDouble-Objekte. MQL5 und MQL4 kompatibel!
Eine Bibliothek für gängige Rundungsmethoden in der MQL-Entwicklung, primitive Wrapper-Klasse für Typ (double) und Vektor für CDouble-Objekte. MQL5 und MQL4 kompatibel!
Version 1.02: (2018.02.18)
Version 1.01:
Autor: nicholi shen