2016-07-11 12 views
1

Ich versuche, ein Char *, das nur einen Gleitkommawert enthält, in einen Typ-Gleitkommawert zu konvertieren, aber sowohl sscanf_s als auch atof produzieren beide das gleiche ungültige Ergebnis.Warum gibt es einen Verlust an Genauigkeit beim Konvertieren von char * in float mit sscanf_s oder atof?

char t[] = "2.10"; 
float aFloat(0.0f), bFloat(0.0f); 

sscanf_s(t, "%f", &aFloat); 
bFloat = atof(t); 

Ausgang:

aFloat: 2.09999990 
bFloat: 2.09999990 

Wenn ich ähnliche Fragen in einem Versuch, sah die Antwort, die ich ohne Erfolg versucht, ihre Lösungen zu ermitteln.

Converting char* to float or double

Die Lösung hier gegeben war ‚stdlib.h‘ enthalten, und so änderte ich den Anruf nach tun, um einen expliziten Aufruf ‚std :: atof‘, aber noch kein Glück atof.

+6

Nicht alle Werte sind genau darstellbar. Siehe auch: http://stackoverflow.com/questions/588004/is-floating-point-math-broken – NathanOliver

+0

Gleitkomma! = Real. Willkommen in der Binärdatei. Siehe Link von @ NathanOliver. – davidbak

+1

Nur eine kleine Korrektur zu Ihrer Frage. Ihr Ergebnis ist einwandfrei und korrekt. Ihre Annahmen und Erwartungen sind ungültig. – Ped7g

Antwort

3

Leider können nicht alle Fließkommawerte explizit in binärer Form dargestellt werden. Sie werden das gleiche Ergebnis, wenn Sie sagen

float myValue = 2.10; 
+1

Danke. Hat das keine großen Auswirkungen auf Finanzanwendungen? – MikeO

+1

@MikeO Nicht wirklich, da Sie den Wert von Cents immer als ganzzahligen Wert speichern und dann in Teile der Währung und Cents aufteilen können, indem Sie für Anzeigezwecke durch 100 teilen/umwandeln. –

+1

@MikeO Es hat große Auswirkungen auf Finanzanwendungen, wenn Sie nicht auf Ungenauigkeiten vorbereitet sind. Sie benötigen eine konsistente Rundungsstrategie, um zu vermeiden, dass gebrochene Pfennige doppelt gezählt werden oder dass sie abgeschnitten werden. Es wird dringend empfohlen, für diese Berechnungen einen festen numerischen Typ zu verwenden. – tadman

3

ich die ausgezeichnete Antwort in den Kommentaren sehen fehlt (oder ich habe es nicht dort finden leicht) eine andere Möglichkeit, wie sie damit umgehen.

Sie sollten geschrieben haben, warum Sie Gleitkommazahl benötigen. Wenn Sie zufällig mit monetären Beträgen arbeiten (und nicht zu großen), können Sie einen benutzerdefinierten Parser für Eingabewerte und einen benutzerdefinierten Formatierer für die Ausgabe von Werten erstellen, um ihn als 64-Bit-Integer (* 100) zu lesen und in Ihrem Ganzen zu arbeiten Anwendung mit 100 * Betragswerten. Wenn Sie mit sehr großen Mengen arbeiten, verwenden Sie eine Bibliothek für große Zahlen, oder Sie können Ihre eigenen mit char * Zahlen arbeiten.

Es ist ein Spezialfall von Fixed-point arithmetic.

Wenn Sie daran interessiert sind, "nur um das zu lösen", ohne zu viel zu programmieren, gehen Sie trotzdem zur großen Zahlenbibliothek, selbst die * 100-Festkomma-Variante ist einfach mit Fehlern zu schreiben - wenn Sie das erste Mal sind haben nicht genügend Ressourcen, um es richtig zu machen (TDD empfohlen).

Aber unbedingt lernen, wie die Zahlen im Computer gespeichert sind, und warum float/double nicht alle Zahlen darstellen kann. Float 2.1 für Computer (Basis 2 intern verwendet) ist vergleichbar mit Mensch 1/3, die nicht in der Basis 10 ohne unendliche Anzahl von Dezimalstellen dargestellt werden kann (und wie 1.0 == 0.99999... in Basis 10). (Danke @ tobi303)


Nach dem neuen Kommentar zu lesen, wenn „Hat dies keinen großen Einfluss auf Finanzanwendungen haben?“

Antwort: Nein, Null Auswirkungen, niemand vernünftig (und professionell) würde finanzielle Anwendung mit Floats oder Doubles erstellen.

+1

"ähnliche Situation, wie menschliche Basis 10 Format kann nicht irrationale Zahlen ohne unendliche Nachkommastellen darstellen" sorry Ich muss widersprechen. Das hat wenig mit Irrationalen zu tun. Nehmen Sie 1/3 in der Basis 10, dies wäre eine viel bessere Gleichheit von 2.1 (in der Basis 10), die keine endliche Anzahl von Ziffern in der Basis 2 aufweist – user463035818