Base class:
// Basic double representation class class ea_dbl { // Internal storage private: double m_dbl; double m_rounding; bool m_bPRound; bool m_bEmpty; long m_long; long m_precision; long m_saved; long m_points; long m_pips; long m_ticks; // Object handlers public: void ea_dbl() { m_dbl = 0; m_saved = Digits() + 3; SetPrecision((int)m_saved); SetRounding(); m_bEmpty = true; } void ea_dbl(const double inVal) { m_dbl = inVal; m_saved = Digits() + 3; SetPrecision((int)m_saved); SetRounding(); } void ea_dbl(const ea_dbl& inVal) { m_dbl = inVal.Get(); m_saved = inVal.GetDigits(); SetPrecision((int)m_saved); SetRounding(inVal.GetRounding()); } void ~ea_dbl() { return; } // Public interface public: // Virtual interface virtual double Get() const { return(GetRawDouble()); } virtual void SetRounding(const bool bPrecise = false) { double r = 0; m_bPRound = bPrecise; if(m_bPRound) { r = (4.9 / ((double)m_points*10)); } m_rounding = r; } virtual bool GetRounding() const { return(m_bPRound); } // Default interface void SetPrecision(const int inVal = 8) { m_precision = (long)inVal; m_points = (long)MathPow(10, m_precision); m_pips = (long)MathPow(10, (m_precision + 1) - Digits()); m_ticks = (long)MathPow(10, m_precision - Digits()); update(); } long GetLong() const { return(m_long); } double GetDouble() const { return(to_double(m_long)); } double GetRawDouble() const { return(m_dbl); } long GetDigits() const { return(m_precision); } void CopyPrecision(const ea_dbl &inVal) { SetPrecision((int)inVal.GetDigits()); } // Sync provider (digit-sync between objects) void _sync() { SetPrecision((int)m_saved); } long _sync(ea_dbl &inVal) { return(_sync(inVal._sync(m_precision))); } long _sync(const long inVal) { m_saved = m_precision; if(inVal < m_precision) { SetPrecision((int)inVal); } return(m_precision); } void _unsync(ea_dbl &inVal) { _sync(); inVal._sync(); } // Set and get different types of digits/values void ticks(const long inVal) { m_dbl = to_double((inVal*m_ticks)); update(); } long ticks() const { return(m_long/m_ticks); } void pips(const long inVal) { m_dbl = to_double((inVal*m_pips)); update(); } long pips() const { return(m_long/m_pips); } void points(const long inVal) { m_dbl = to_double((inVal*m_points)); update(); } long points() const { return(m_long/m_points); } // Internal helper functions private: // Keep internal data updated void update() { m_bEmpty = false; m_long = to_long(m_dbl); return; } protected: // Helpers, securing correct digit count handling long to_ticks(const long inVal) const { return(inVal/m_ticks); } long to_pips(const long inVal) const { return(inVal/m_pips); } long to_points(const long inVal) const { return(inVal/m_points); } long from_ticks(const long inVal) const { return(inVal*m_ticks); } long from_pips(const long inVal) const { return(inVal*m_pips); } long from_points(const long inVal) const { return(inVal*m_points); } long to_long(const double inVal) const { string str = DoubleToString(MathRound((double)m_points * (inVal + m_rounding)), 0); return( StringToInteger(str) ); } double to_double(const long inVal) const { string str = IntegerToString(inVal, (int)m_precision, 0x30); bool bNeg = false; if(StringReplace(str, "-", "") > 0) { bNeg = true; } string missing_zeroes = ""; for(int pos = StringLen(str) - (int)m_precision; pos <= 0; pos++) { StringAdd(missing_zeroes, "0"); } StringAdd(missing_zeroes, str); StringConcatenate(str, bNeg?"-":"", StringSubstr(missing_zeroes, 0, StringLen(missing_zeroes) - (int)m_precision), ".", StringSubstr(missing_zeroes, StringLen(missing_zeroes) - (int)m_precision)); return(StringToDouble(str)); } // Operators public: // Generic Operators: Operators: !, ++, -- // ea_dbl selfreferencing operators virtual bool operator ! () const { return((m_bEmpty) || (m_long == 0)); } virtual void operator ++ () { m_dbl += 1.0/(MathPow(10, Digits())); update(); } virtual void operator -- () { m_dbl -= 1.0/(MathPow(10, Digits())); update(); } // Operators: ==, !=, <, >, <=, >=, +, -, *, /, %, =, +=, -=, *=, /=, %= // dbl class object reference virtual bool operator == (ea_dbl &inVal) { _sync(inVal); bool bEqual = (m_long == inVal.GetLong()); _unsync(inVal); return(bEqual); } virtual bool operator != (ea_dbl &inVal) { return(!operator == (inVal)); } virtual bool operator > (ea_dbl &inVal) { _sync(inVal); bool bEqual = (m_long > inVal.GetLong()); _unsync(inVal); return(bEqual); } virtual bool operator < (ea_dbl &inVal) { _sync(inVal); bool bEqual = (m_long < inVal.GetLong()); _unsync(inVal); return(bEqual); } virtual bool operator >= (ea_dbl &inVal) { _sync(inVal); bool bEqual = (m_long >= inVal.GetLong()); _unsync(inVal); return(bEqual); } virtual bool operator <= (ea_dbl &inVal) { _sync(inVal); bool bEqual = (m_long <= inVal.GetLong()); _unsync(inVal); return(bEqual); } ea_dbl operator + (ea_dbl &inVal) { _sync(inVal); long lRetval = (m_long + inVal.GetLong()); _unsync(inVal); return(to_double(lRetval)); } ea_dbl operator - (ea_dbl &inVal) { _sync(inVal); long lRetval = (m_long - inVal.GetLong()); _unsync(inVal); return(to_double(lRetval)); } ea_dbl operator * (ea_dbl &inVal) { _sync(inVal); long lRetval = (m_long * inVal.GetLong()); _unsync(inVal); return(to_double(lRetval)); } ea_dbl operator / (ea_dbl &inVal) { _sync(inVal); long lRetval = (m_long / inVal.GetLong()); _unsync(inVal); return(to_double(lRetval)); } ea_dbl operator % (ea_dbl &inVal) { _sync(inVal); long lRetval = (m_long % inVal.GetLong()); _unsync(inVal); return(to_double(lRetval)); } void operator = (ea_dbl &inVal) { _sync(inVal); m_long = inVal.GetLong(); m_dbl = to_double(m_long); _unsync(inVal); return; } void operator += (ea_dbl &inVal) { _sync(inVal); m_long += inVal.GetLong(); m_dbl = to_double(m_long); _unsync(inVal); return; } void operator -= (ea_dbl &inVal) { _sync(inVal); m_long -= inVal.GetLong(); m_dbl = to_double(m_long); _unsync(inVal); return; } void operator *= (ea_dbl &inVal) { _sync(inVal); m_long *= inVal.GetLong(); m_dbl = to_double(m_long); _unsync(inVal); return; } void operator /= (ea_dbl &inVal) { _sync(inVal); m_long /= inVal.GetLong(); m_dbl = to_double(m_long); _unsync(inVal); return; } void operator %= (ea_dbl &inVal) { ticks((ticks()%inVal.ticks())); } // double as input virtual bool operator == (const double inVal) const { return(m_long == to_long(inVal)); } bool operator != (const double inVal) const { return(!operator == (inVal)); } virtual bool operator > (const double inVal) const { return(m_long > to_long(inVal)); } virtual bool operator < (const double inVal) const { return(m_long < to_long(inVal)); } virtual bool operator >= (const double inVal) const { return(m_long >= to_long(inVal)); } virtual bool operator <= (const double inVal) const { return(m_long <= to_long(inVal)); } double operator + (const double inVal) const { return(m_dbl+inVal); } double operator - (const double inVal) const { return(m_dbl-inVal); } double operator * (const double inVal) const { return(m_dbl*inVal); } double operator / (const double inVal) const { return(m_dbl/inVal); } double operator % (const double inVal) const { return((double)((m_long/m_ticks)%(to_long(inVal)/m_ticks))); } void operator = (const double inVal) { m_dbl = inVal; update(); } void operator += (const double inVal) { m_dbl += inVal; update(); } void operator -= (const double inVal) { m_dbl -= inVal; update(); } void operator *= (const double inVal) { m_dbl *= inVal; update(); } void operator /= (const double inVal) { m_dbl /= inVal; update(); } void operator %= (const double inVal) { m_dbl = (double)((m_long/m_ticks)%(to_long(inVal)/m_ticks)); update(); } };
Ehrlich gesagt - ich glaube niemand braucht das!
Für die optische Darstellung gibt es DoubleToString(), StringFormate(), Printformate().
Für die interne Berechnung NormalizeDouble().
und für Vergleiche müsste man sich halt angewöhnen
statt zB.: if( double1 == double2)
einfach: if ( abs(double1-double2)> _Point*0.1 )
Fehlt noch etwas?
Ehrlich gesagt - ich glaube niemand braucht das!
Für die optische Darstellung gibt es DoubleToString(), StringFormate(), Printformate().
Für die interne Berechnung NormalizeDouble().
und für Vergleiche müsste man sich halt angewöhnen
statt zB.: if( double1 == double2)
einfach: if ( abs(double1-double2)> _Point*0.1 )
Fehlt noch etwas?
Danke für die Antwort.
Ein sehr nützlicher Ansatz, den du da empfiehlst. - Ein sehr Pragmatischer. Das würde ich gerne adaptieren.
Allerdings empfinde ich die Handhabung von Double und Integer sowie die Einheiten Ticks, Pips und Points immer wieder verwirrend. Als Erweiterungsbeispiel habe ich eine Art "Magnet" angefügt.
Danke für deine Anregung.

- 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.
Hallo Community,
das Problem mit der Double (Float). Ein Thame, dass immer wieder in den Foren auftaucht.
Warum gibt es eigentlich Probleme mit Doubles oder Float Datentypen? - An und für sich ist das einfach zu beantworten: Sie werden falsch benutzt. Eine recht harte These, doch aus mathematischer Sicht ist das ganz einfach zu erklären: Unendliche Genauigkeit bei endlicher Speicherfläche.
Nun zum Thema: Double und Float Variablen sind Speicherplätze im (Haupt)Speicher, die eine "Interpretationsinformation" und eine Datengröße erhalten.
Wenn wir uns nun Vorstellen, eine Zahl mit Nachkommastellen, so ist diese Zahl (je nach Genauigkeit) mit einer bestimmten Menge an Nullen nach dem Komma versehen. - An einer dieser Stellen, irgendwo zwischen den Nachkommastellen, hört der Speicherplatz auf. Genau an dieser Stelle tritt das Problem mit der Genauigkeit auf. Um das nun "technisch" in den Griff zu bekommen, wurde der Speicherplatz für die Zahl in Zwei (eigentlich Drei) Teile zerlegt. Hier die Definition (Wikipedia):
Bei der Gleitkommadarstellung werden 11 Bit für den Exponenten verwendet und ein Bit für das Vorzeichen, die restlichen 52 Bit stehen für die eigentliche Zahlendarstellung (Mantisse) zur Verfügung. Eine Präzision von 53 Bit bedeutet umgerechnet ins Dezimalsystem eine ungefähre Genauigkeit auf 16 Stellen im Dezimalsystem ( {\displaystyle 53\log _{10}(2)\approx 15.955} 53\log _{{10}}(2)\approx 15.955).
Somit stehen bestimmte Mengen an Zahlen zu Verfügung, jedoch leider nicht alle zwischen den speicherbaren Stellen, denn ein halbes Bit kann man nicht speichern. :-)
Das führt zu Nebeneffekten im Umgang mit double/float Werten in der Programmierung. (Besonders beim Vergleich und im Besonderen in Kombination mit Integer-Werten). Da ich immer wieder über diese Ungenauigkeit stolperte, war es mir ein Anliegen, dieses "Problem" ganzheitlich zu lösen...
Mein erster Entwurf ist hier und ich würde diesen gerne mit euch diskutieren, sofern es denn Interesse daran gibt. Ziel ist, das Konstrukt zu optimieren und noch weiter zu generalisieren.
Findige Köpfe haben sicher einige gute Ideen zu diesem Ansatz.