Dies sind drei praktische Funktionen für den Vergleich und die Rundung von Fließkommazahlen und die Formatierung von Geld:
1. `bool DoubleEquals(double x, double y, double eps)` vergleicht zwei Double-Werte `x` und `y` mit einem gegebenen Epsilon-Wert `eps` und gibt einen boolschen Wert zurück, der angibt, ob sie innerhalb der gegebenen Toleranz gleich sind.
2. `double RoundTo(double value, int digits)` rundet einen double-Wert `value` auf die angegebene Anzahl von Dezimalstellen `digits`.
3. `string FormatMoney(double amount)` formatiert einen Double-Wert `amount` als String, der einen Währungsbetrag darstellt. Es formatiert den Betrag mit zwei Dezimalstellen, ersetzt den Dezimalpunkt durch ein Komma und fügt alle drei Stellen Leerzeichen ein, um die Lesbarkeit zu verbessern. Außerdem wird am Ende das Währungssymbol aus `AccountInfoString(ACCOUNT_CURRENCY)` angefügt.
Vielen Dank dafür. Allerdings sind diese Funktionen bereits in der Bibliothek implementiert (sogar mit stabileren Ergebnissen als die Ihren), aber mit anderen Namen.
// Prüfen, ob zwei Zahlen bis auf "n" Stellen genau gleich sind.int Compare(constdouble a, constdouble b, constint digits);
bool EqualDoubles(double a, double b, int significantDigits = 15);
bool IsClose(constdouble a, constdouble b, constint maxDifferentSignificantDigits = 2)
// Genaue Dezimalrundung, um unerwartete Ergebnisse zu vermeiden.double Round(constdouble v);
double Round(constdoublevalue, constint digits);
double Round(constdoublevalue, constdouble step);
// Formatiert Double mit Tausendertrennzeichen und angegebenen Dezimalstellen.string FormatDouble(constdouble number, constint digits, conststring separator=",");
Ich hatte erwartet, dass der zweite Druck "0.0001" sein sollte.
Wenn es ein Fehler ist, wie kann man ihn beheben? Wenn nicht, was ist in meinem Code falsch?
Vielen Dank!
Drucken Sie die hexadezimalen Darstellungen aus und Sie werden verstehen, dass die Spanne weit vom wahren realen Wert 0,0001 entfernt ist (das liegt an Rundungsfehlern bei der Subtraktion).
jonlinper #: Ich hatte erwartet, dass der zweite Ausdruck "0,0001" lautet.
Fließkommazahlen haben eine unendliche Anzahl von Dezimalstellen. Es liegt an dir, dass du das Fließkommaformat nicht verstehst und dass einige Zahlen nicht exakt dargestellt werden können. (wie 1/10.) Doppeltes Gleitkommaformat - Wikipedia
Die Fließkommadarstellung hat eine unendliche Anzahl von Dezimalstellen. Es liegt an Ihnen, dass Sie das Fließkomma-Format nicht verstehen und dass einige Zahlen nicht exakt dargestellt werden können. (wie 1/10.) Doppeltes Gleitkommaformat - Wikipedia
Lieber William, danke für die Klarstellung, allerdings stimme ich dir nicht zu, was die "unendliche Anzahl von Dezimalstellen" angeht. FP-Zahlen haben tatsächlich eine endliche Anzahl von Dezimalstellen. (Zum Beispiel hat 0,1 genau 52 Ziffern nach dem Komma).
Verwenden Sie DoubleToStringExact(0.1) aus meiner Bibliothek, um sie alle zu drucken. Sie können auch die vollständige Dezimalzeichenfolge mit diesem Rechner hier überprüfen: https://www.exploringbinary.com/floating-point-converter/
Beachten Sie auch, dass die vollständige Dezimalzeichenfolge immer mit der Ziffer "5" enden muss.
Wie kann man am besten nur signifikante Ziffern mit Doppelzahlen drucken?
double Trunc(constdoublevalue, constint digits);
Diese Funktion funktioniert gut für 99,9% der Zahlen, aber sie hat Probleme mit runden Zahlen wie 1.0000000000
Mein Problem ist, dass ich die nicht signifikanten Ziffern entfernen muss, und aus irgendeinem Grund bin ich nicht in der Lage, dies nur mit @Trunc zu tun,
also habe ich etwas verwendet wie:
string Normalize_Double_ToString(double n, int d)
{
// Schritt 1 - es hilft, Nullen am Ende auszuschließen
n = Round(n, d);
// Schritt 2 - Zählen der Anzahl der signifikanten Dezimalstellenint sd = GetSignificantDecimals(n);
// Schritt 3 - wir wollen nicht mehr als in @d angegebenif (sd > d){ sd = d; }
// Schritt 4 - Entfernen unerwünschter Dezimalstellen ohne negative Rundung double t = Trunc(n, sd);
// Fehlersuche//PrintFormat("%s [%d] [%d] :: %s", DoubleToString(n, DBL_DIG), d, sd, DoubleToString(t, sd));// Schritt 5 - Genauigkeit einstellenstring s = DoubleToString(t, sd);
return s;
}
Es funktioniert genau wie benötigt und gibt mir die kleinste mögliche Zeichenkette für alle Zahlen, aber ich frage mich, ob es optimiert werden kann und immer noch die kleinste Zeichenkette mit runden Zahlen wie 1.00000000
Cristian Dan Fechete runden Zahlen wie 1.0000000000
Mein Problem ist, dass ich nicht signifikante Ziffern entfernen muss, und aus irgendeinem Grund bin ich nicht in der Lage, es nur mit @Trunc zu tun,
also benutze ich etwas wie:
Es funktioniert genau wie benötigt und gibt mir die kleinste mögliche Zeichenfolge für alle Zahlen, aber ich frage mich, ob es optimiert werden kann und immer noch kleinste Zeichenfolge mit runden Zahlen wie 1.00000000
Danke für die Hilfe!
Entschuldigung, Sie müssen verstehen, was signifikante Ziffern sind, da ich finde, dass Ihr Code die grundlegenden Konzepte verwirrt.
Was versuchen Sie zu tun? Bitte erklären Sie es in einfachen Worten, ohne Code. Geben Sie ein Beispiel dafür, was Sie falsch finden und was Ihre Erwartungen sind.
amrali #: Entschuldigung, Sie müssen verstehen, was signifikante Ziffern sind, da ich finde, dass Ihr Code die grundlegenden Konzepte verwirrt.
Was versuchen Sie zu tun? Bitte erklären Sie es in einfachen Worten, ohne Code. Geben Sie ein Beispiel dafür, was Sie falsch finden und was Ihre Erwartungen sind.
Vielen Dank für Ihre Zeit, und ja, ich bin mir nicht ganz sicher, ob ich "signifikante Ziffern" verstehe.
Im Grunde genommen muss ich die kürzestmögliche Zahl "drucken". Zum Beispiel:
1.0000000 -> 1
1.0090000 -> 1.009
123.00100 -> 123.001
Für mich bedeutet 'signifikante Ziffern': Ziffern, die den Wert einer Zahl ändern, wenn sie entfernt werden, also sind nachgestellte Nullen nicht signifikant.
Übrigens, seit dem letzten Windows-Update führt die Funktion Round(double, int) dazu, dass MT4 blockiert. Der erste Code, den ich gepostet habe, funktionierte perfekt und seit gestern Abend friert der MT4-Client komplett ein.
Vielen Dank für Ihre Zeit, und ja, ich bin mir nicht ganz sicher, ob ich "signifikante Ziffern" verstehe.
Ich muss im Grunde die kürzestmögliche Zahl "drucken". Zum Beispiel:
1.0000000 -> 1
1.0090000 -> 1.009
123.00100 -> 123.001
Für mich bedeutet "signifikante Ziffern": Ziffern, die den Wert einer Zahl verändern, wenn sie entfernt werden, also sind nachgestellte Nullen nicht signifikant.
Übrigens, seit dem letzten Windows-Update führt die Funktion Round(double, int) dazu, dass MT4 blockiert. Der erste Code, den ich gepostet habe, funktionierte perfekt und seit gestern Abend friert der MT4-Client komplett ein.
Die Print()-Funktion oder die Umwandlung von double in string wie (string)dbl liefert die kürzest mögliche Anzahl signifikanter Ziffern, ohne dass man die Zahl vorher manipulieren muss. Dies ist eine eingebaute Funktion in MQL. (Ich habe dem Entwicklerteam bereits eine Lösung vorgeschlagen, und sie wurde in den Code aufgenommen).
Alles, was Sie tun müssen, ist:
string num_str = string(number).
oder: Print(number);
Aus diesem Grund ist eine spezielle Funktion zum Drucken oder Formatieren von Zahlen in die kürzest mögliche Zeichenkette innerhalb der Bibliothek nicht erforderlich, die Funktionalität wird bereits von der MQL-Sprache unterstützt.
Verwenden Sie DoubleToString() nur, wenn Sie die Anzahl der Ziffern nach dem Dezimalpunkt kontrollieren müssen. Wenn der Parameter digits größer ist als die Dezimalstellen in Ihrer Zahl, werden die 0's an den zurückgegebenen String angehängt, zum Beispiel
DoubleToString(1.09, 5) gibt die Zeichenkette "1.09000" zurück.
Ist der Parameter digits kleiner als die Dezimalstellen der Zahl, wird die Zahl angenähert, z. B. DoubleToString(1.12345, 2) gibt die Zeichenfolge "1.12" zurück. Die Verwirrung entsteht durch die Unfähigkeit, Zahlen von Zeichenketten zu unterscheiden.
Beachten Sie, dass Zahlen, die mit Nullen enden, wie 1.09, 1.090, 1.0900, 1.09000 und 1.090000 als dieselbe Double-precision fp Zahl in Variablen gespeichert werden. Diese können nur durch direkte Eingabe durch den Benutzer als manuelle Eingaben erreicht werden. Innerhalb des Programms werden alle diese Zahlen als dieselbe Zahl, nämlich 1,09, gespeichert, nachgestellte 0 werden nicht gespeichert.
double a = 1.09;
double b = 1.090000;
Print(a); // "1,09"
Print(b); // "1,09"
Rundungsfunktionen wie round, ceil und floor ändern (approximieren) die eingegebene Zahl in eine andere Zahl, die die nächstgelegene Double-Zahl mit der angegebenen Anzahl von Nachkommastellen ist, oder die Zahl, die die angegebene Gesamtzahl signifikanter Ziffern enthält, im Falle von RoundToSignificantDigits().
Ich hoffe, das klärt die Verwirrung über die Konvertierung von doppelgenauen fp-Zahlen in einen String.
3. `string FormatMoney(double amount)` formatiert einen Double-Wert `amount` als String, der einen Währungsbetrag darstellt. Es formatiert den Betrag mit zwei Dezimalstellen, ersetzt den Dezimalpunkt durch ein Komma und fügt alle drei Stellen Leerzeichen ein, um die Lesbarkeit zu verbessern. Außerdem wird am Ende das Währungssymbol aus `AccountInfoString(ACCOUNT_CURRENCY)` angefügt.
Vielen Dank dafür. Allerdings sind diese Funktionen bereits in der Bibliothek implementiert (sogar mit stabileren Ergebnissen als die Ihren), aber mit anderen Namen.
Hallo @amrali, danke für deinen Beitrag.
Vielleicht ist das ein Fehler?
Ich hatte erwartet, dass der zweite Druck "0.0001" sein sollte.
Wenn es ein Fehler ist, wie kann man ihn beheben? Wenn nicht, was ist in meinem Code falsch?
Ich danke Ihnen.
Hallo @amrali, vielen Dank für Ihren Beitrag.
Vielleicht ist dies ein Fehler?
Ich hatte erwartet, dass der zweite Druck "0.0001" sein sollte.
Wenn es ein Fehler ist, wie kann man ihn beheben? Wenn nicht, was ist in meinem Code falsch?
Vielen Dank!
Drucken Sie die hexadezimalen Darstellungen aus und Sie werden verstehen, dass die Spanne weit vom wahren realen Wert 0,0001 entfernt ist (das liegt an Rundungsfehlern bei der Subtraktion).
Sie müssen also Rundungsprozeduren anwenden.
Es gibt kleine Unterschiede, die Sie beachten sollten:
StripError() rundet an der 16 . Stelle 0.00009999999999998899 (0's werden nicht gezählt).
Round(x, 16) rundet auf die 16. Stelle nach dem Komma 0.00009999999999998899
Fließkommazahlen haben eine unendliche Anzahl von Dezimalstellen. Es liegt an dir, dass du das Fließkommaformat nicht verstehst und dass einige Zahlen nicht exakt dargestellt werden können. (wie 1/10.)
Doppeltes Gleitkommaformat - Wikipedia
Siehe auch Der == Operand. - MQL4 Programmierforum (2013)
Wenn Sie die korrekte Anzahl von Ziffern sehen wollen, konvertieren Sie sie in eine Zeichenkette mit der richtigen/gewünschten Genauigkeit.
Frage zu decima von marketinfo() - MQL4 Programmierforum (2016)
Die Fließkommadarstellung hat eine unendliche Anzahl von Dezimalstellen. Es liegt an Ihnen, dass Sie das Fließkomma-Format nicht verstehen und dass einige Zahlen nicht exakt dargestellt werden können. (wie 1/10.)
Doppeltes Gleitkommaformat - Wikipedia
Siehe auch Der == Operand. - MQL4-Programmierforum (2013)
Wenn Sie die korrekte Anzahl von Ziffern sehen wollen, konvertieren Sie sie in eine Zeichenkette mit der richtigen/gewünschten Genauigkeit.
question about decima of marketinfo() - MQL4 programming forum (2016)
Wie kann man am besten nur signifikante Ziffern mit Doppelzahlen drucken?
Diese Funktion funktioniert gut für 99,9% der Zahlen, aber sie hat Probleme mit runden Zahlen wie 1.0000000000
Mein Problem ist, dass ich die nicht signifikanten Ziffern entfernen muss, und aus irgendeinem Grund bin ich nicht in der Lage, dies nur mit @Trunc zu tun,
also habe ich etwas verwendet wie:
Es funktioniert genau wie benötigt und gibt mir die kleinste mögliche Zeichenkette für alle Zahlen, aber ich frage mich, ob es optimiert werden kann und immer noch die kleinste Zeichenkette mit runden Zahlen wie 1.00000000
Ich danke Ihnen für Ihre Hilfe.
Ich habe gerade festgestellt, dass ich die
Eine leicht modifizierte Version Ihrer
und dies ist der Code
Mein Problem ist, dass ich nicht signifikante Ziffern entfernen muss, und aus irgendeinem Grund bin ich nicht in der Lage, es nur mit @Trunc zu tun,
also benutze ich etwas wie:
Es funktioniert genau wie benötigt und gibt mir die kleinste mögliche Zeichenfolge für alle Zahlen, aber ich frage mich, ob es optimiert werden kann und immer noch kleinste Zeichenfolge mit runden Zahlen wie 1.00000000
Danke für die Hilfe!
Entschuldigung, Sie müssen verstehen, was signifikante Ziffern sind, da ich finde, dass Ihr Code die grundlegenden Konzepte verwirrt.
Vielen Dank für Ihre Zeit, und ja, ich bin mir nicht ganz sicher, ob ich "signifikante Ziffern" verstehe.
Im Grunde genommen muss ich die kürzestmögliche Zahl "drucken". Zum Beispiel:
1.0000000 -> 1
1.0090000 -> 1.009
123.00100 -> 123.001
Für mich bedeutet 'signifikante Ziffern': Ziffern, die den Wert einer Zahl ändern, wenn sie entfernt werden, also sind nachgestellte Nullen nicht signifikant.
Übrigens, seit dem letzten Windows-Update führt die Funktion Round(double, int) dazu, dass MT4 blockiert. Der erste Code, den ich gepostet habe, funktionierte perfekt und seit gestern Abend friert der MT4-Client komplett ein.
Vielen Dank für Ihre Zeit, und ja, ich bin mir nicht ganz sicher, ob ich "signifikante Ziffern" verstehe.
Ich muss im Grunde die kürzestmögliche Zahl "drucken". Zum Beispiel:
1.0000000 -> 1
1.0090000 -> 1.009
123.00100 -> 123.001
Für mich bedeutet "signifikante Ziffern": Ziffern, die den Wert einer Zahl verändern, wenn sie entfernt werden, also sind nachgestellte Nullen nicht signifikant.
Übrigens, seit dem letzten Windows-Update führt die Funktion Round(double, int) dazu, dass MT4 blockiert. Der erste Code, den ich gepostet habe, funktionierte perfekt und seit gestern Abend friert der MT4-Client komplett ein.