2009-06-18 5 views
6

Ich stehe vor einem Problem und kann es nicht lösen. Brauche Hilfe von Gurus. Hier ist ein Beispielcode: -C++: Wie konvertiert man von Float zu String ohne Rundung, Trunkierung oder Padding?

float f=0.01f; 
printf("%f",f); 

wenn wir Wert in Variablen überprüfen, während f Debuggen enthält ‚0,0099999998‘ Wert und Ausgabe von printf ist 0,010000.

a. Gibt es eine Möglichkeit, den Compiler dazu zu zwingen, der Variablen vom Typ float die gleichen Werte zuzuweisen?

b. Ich möchte Float in String/Character Array konvertieren. Wie ist es möglich, dass nur und genau der gleiche Wert in ein String/Zeichen-Array konvertiert wird? Ich möchte sicherstellen, dass keine Nullen aufgefüllt werden, keine unerwünschten Werte aufgefüllt werden, keine Änderungen der Ziffern wie im obigen Beispiel.

Antwort

2

Werfen Sie einen Blick auf diese C++ reference. Insbesondere der Abschnitt über die Genauigkeit:

float blah = 0.01; 
printf ("%.2f\n", blah); 
+0

Ich denke, er hat ein Problem mit Floats nicht verdoppelt – Aamir

+0

hehe ... das ist cool. Ich nehme an, dass der ursprüngliche Downvote möglicherweise wegen meiner ersten, sehr knappen Antwort (ohne Quellcode) gewesen ist, und auch fair genug;). – RedBlueThing

+0

Könnte auch sein, weil ich das ganze Float Point Repräsentation Thema ignoriert habe und die Frage auf einer ziemlich oberflächlichen Ebene beantwortet habe. – RedBlueThing

2

Es gibt unzählige reelle Zahlen.

Es gibt nur eine endliche Anzahl von Werten, die die Datentypen float, double und long double annehmen können.

Das heißt, es wird unzählige reelle Zahlen geben, die nicht genau mit diesen Datentypen dargestellt werden können.

6

Es ist unmöglich, eine Basis 10 Dezimalzahl mit Basis 2-Werten genau darzustellen, außer für eine sehr kleine Anzahl von Werten (wie 0,25). Um zu bekommen, was Sie brauchen, müssen Sie von den Float/Double-Built-in-Typen zu einer Art Dezimalzahl-Paket wechseln.

1

Der Grund, dass Ihr Debugger Ihnen einen anderen Wert gibt, wird in Mark Ransoms Post gut erklärt.

In Bezug auf das Drucken eines Gleitkommas ohne Aufrundung, Abschneiden und mit vollerer Genauigkeit fehlt Ihnen der Präzisionsspezifizierer - Standardpräzision für printf ist in der Regel 6 Nachkommastellen.

versuchen die folgenden eine Genauigkeit von 10 Stellen zu erhalten:

float amount = 0.0099999998; 
printf("%.10f", amount); 

Als Randnotiz, eine C++ Art und Weise (im Vergleich zu C-Stil), Dinge zu tun, ist mit cout:

float amount = 0.0099999998; 
cout.precision(10); 
cout << amount << endl; 
0

Sie müssten Ihre Plattformstandards konsultieren, um zu bestimmen, wie Sie das richtige Format am besten ermitteln. Sie müssten es als * b^C anzeigen, wobei 'a' die integrale Komponente ist, die das Zeichen 'b' enthält Implementierung definiert (Wahrscheinlich durch einen Standard festgelegt), und "C" ist der für diese Zahl verwendete Exponent.

Alternativ könnte man es auch einfach in hex darstellen, es würde aber für einen Menschen nichts bedeuten, und es wäre immer noch binär für alle praktischen Zwecke. (! Und wie portable)

0

Um Ihre zweite Frage zu beantworten:

ist es möglich, genau und eindeutig Schwimmer als Strings darstellen. Dies erfordert jedoch eine hexadezimale Darstellung. Zum Beispiel ist 1/16 = 0,1 und 10/16 0.A.

Mit Hexadezimalen können Sie eine kanonische Darstellung definieren.Ich würde persönlich eine feste Anzahl von Ziffern verwenden, die die zugrunde liegende Anzahl von Bits darstellen, aber Sie könnten auch entscheiden, nachfolgende Nullen zu entfernen. Es ist keine Verwirrung möglich, bei der die nachfolgenden Ziffern Null sind.

Da die Darstellung exakt ist, sind die Umsätze reversibel: f==hexstring2float(float2hexstring(f))

3

Sie boost::lexical_cast auf diese Weise nutzen könnten:

float blah = 0.01; 
string w = boost::lexical_cast<string>(blah); 

Variable w Textwert ,00999999978 enthalten wird. Aber ich kann nicht sehen, wann du es wirklich brauchst.

Es wird bevorzugt, boost::format für genaue Formatierung float als Zeichenfolge zu verwenden. Der folgende Code zeigt, wie es geht:

float blah = 0.01; 
string w = str(boost::format("%d") % blah); // w contains exactly "0.01" now 
0

Für (b), könnten Sie

std::ostringstream os; 
os << f; 
std::string s = os.str(); 
1

Ebenso tun, können Sie die stdlib.h nutzen könnten, dort sind die sprintf, ecvt und fcvt Funktionen (oder zumindest sollte es sein!).

int sprintf(char* dst,const char* fmt,...); 

char *ecvt(double value, int ndig, int *dec, int *sign); 

char *fcvt(double value, int ndig, int *dec, int *sign); 

sprintf die Anzahl der Zeichen gibt es an den String geschrieben, zum Beispiel

float f=12.00; 
char buffer[32]; 
sprintf(buffer,"%4.2f",f) // will return 5, if it is an error it will return -1 

ecvt und fcvt Rückkehr Zeichen static char * Stellen die Null enthält beendet Dezimaldarstellungen der Zahlen, ohne Dezimalpunkt, höchstwertige Zahl zuerst, der Offset des Dezimalpunkts wird in Dez gespeichert, das Vorzeichen in "Vorzeichen" (1 = -, 0 = +) ndig ist die Anzahl der signifikanten Stellen zu speichern e. Wenn dez < 0 dann müssen Sie mit -dec Nullen pror auf den Dezimalpunkt auffüllen. Ich bin unsicher, und Sie arbeiten nicht auf einem Windows7-System (das manchmal nicht alte DOS3-Programme laufen) für TurboC Version 2 für Dos 3 suchen, gibt es noch ein oder zwei Downloads zur Verfügung, es ist ein relativ kleines Programm von Borland ist ein kleiner DOS C/C++ - Editor/Compiler und kommt sogar mit TASM, dem 16-Bit-Maschinencode 386/486 kompilieren, der in den Hilfedateien ebenso behandelt wird wie viele andere nützliche Informationsnuggets. Alle drei Routinen sind in "stdlib.h" oder sollten es sein, obwohl ich festgestellt habe, dass sie auf VisualStudio2010 alles andere als Standard sind, oft überladen mit Funktionen, die sich mit WORD-Zeichen befassen und Sie bitten, ihre eigenen spezifischen Funktionen zu verwenden stattdessen ... "so viel für Standard Bibliothek," Ich murmele fast jedes Mal zu mir selbst, "Vielleicht sie, um ein besseres Wörterbuch zu bekommen!"

1

In Wahrheit mit dem Gleitkomma-Prozessor oder Co-Prozessor oder Abschnitt des Chips selbst (die meisten sind jetzt in die CPU integriert), wird nie zu genauen mathematischen Ergebnissen führen, aber sie geben eine ziemlich grobe Genauigkeit, für mehr genaue Ergebnisse, könnten Sie in Erwägung ziehen, eine Klasse "DecimalString" zu definieren, die nybbles als Dezimalzeichen und Symbole verwendet ... und versuchen Sie, Basis 10 Mathematik mit Strings ... in diesem Fall, je nachdem, wie lange Sie die Strings machen wollen Sie können sogar den Exponententeil komplett eliminieren. Eine Zeichenkette 256 kann 1x10^-254 bis 1^+ 255 in gerader Dezimalzahl mit echtem ASCII darstellen, kürzer, wenn Sie ein Vorzeichen haben wollen, aber dies kann sich als wesentlich langsamer erweisen. Sie könnten dies beschleunigen, indem Sie die Reihenfolge der Ziffern umkehren, also von links nach rechts lesen sie Einheiten, Zehner, Hunderter, Tausender ....

Einfaches Beispiel z. "0021" wird zu 1200 Dies müsste links und rechts "verschoben" werden, um die Dezimalpunkte vor den Routinen auszurichten. Am besten ist es, mit den ADD- und SUB-Funktionen zu beginnen, da Sie dann in der MUL darauf aufbauen und DIV-Funktionen. Wenn Sie auf einer großen Maschine sind, können Sie sie theoretisch so lange machen, wie Ihr Herz es wünschte!