2010-12-16 16 views
12

Ich möchte einen Float-Wert in einen String speichern, ohne zu verlieren oder eine einzelne Genauigkeitsziffer hinzuzufügen.Konvertieren von Float in String, ohne Genauigkeit zu verlieren

Zum Beispiel, wenn mein float-Wert 23.345466467 ist, möchte ich meine Zeichenfolge str = "23.345466467" genaue Ziffern haben.

Ich versuchte CString-Format-Funktion mit% f. Es gibt nur die erste Präzision 6. oder wenn ich% 10 verwende, wenn mein Gleitkommawert weniger als 10 Genauigkeit hat, fügt er etwas mehr Junk-Genauigkeit hinzu. Ich möchte den exakten Gleitkommawert in meine Saite bekommen. Wie macht man das?

+4

Das hängt davon ab, ob Ihr Gleitkommawert 23 ist.345466467 ist genau darstellbar (wahrscheinlich nicht) –

+0

@Mitch: Ich habe mich gefragt, die gleiche Sache. Was wäre der einfachste Weg, um zu prüfen, ob es ist? –

+3

@Mitch Wheat: Ein 'float'-Wert ist immer als String darstellbar, solange die Basis, in die Sie konvertieren, durch 2 teilbar ist. Natürlich ist' 23.345466467' nicht durch einen 'float' an erster Stelle darstellbar. – JeremyP

Antwort

1

Erstens: Sie können Floating nicht in String und zurück konvertieren, ohne wahrscheinlich ein oder zwei Bits zu verlieren. Da es keine 1-zu-1-Konvertierung ist, verwenden sie unterschiedliche Basen.

Für die beste Genauigkeit für Gleitkommatyps Erhaltung:

std::string convert(float value) 
{ 
    std::stringstream ss; 
    ss << std::setprecision(std::numeric_limits<float>::digits10+1); 
    ss << value; 
    return ss.str(); 
} 

Oder allgemeineren

template<typename FloatingPointType> 
std::string convert(FloatingPointType value) 
{ 
    std::stringstream ss; 
    ss << std::setprecision(std::numeric_limits<FloatingPointType>::digits10+1); 
    ss << value; 
    return ss.str(); 
} 

Es Ziffern abgeschnitten würden Sie nicht brauchen, aber halte höchste Präzision möglich.

+0

Wenn ich die höchste Genauigkeit halte, zum Beispiel: wenn ich die Ziffern 10 + 10 verwende, für den Wert 213.2352352345345346f; seine Rückkehr 213.2352294921875; Ich habe nicht verstanden, warum die Junk-Ziffern nach 4-stelliger Genauigkeit kommen. –

+1

@ Rajesh, das ist, weil die Zahl, die Sie wollen, nicht genau durch ein 'float' dargestellt werden kann, sehen Sie die Kommentare zu Ihrer Frage. Wenn es nicht repräsentiert werden kann, kann es einfach nicht dargestellt werden, es gibt sehr wenig, was man dagegen tun kann! Sie müssen einen anderen Ansatz in Erwägung ziehen, kann ein ganzzahliger Exponent/Mantisse sein? – Nim

+1

Sollte das nicht Ziffern10 + 2 sein? Ich schrieb ein schnelles Testprogramm und nur +1 schien mir nicht zu erlauben, die Fließkommazahl durch die Zeichenkette zu durchlaufen. +2 schien jedoch für große und kleine Zahlen zu funktionieren. – MrSlippers

7

Das davon, ob Ihr Float-Wert 23,345466467 genau darstellbaren (wahrscheinlich nicht)

What Every Computer Scientist Should Know About Floating-Point Arithmetic

Why Floating-Point Numbers May Lose Precision

Ich würde auch fragen, warum Sie dies tun müssen, abhängen würde? Wofür verwenden Sie die String-Darstellung? Sind Ihnen die Double- und Decimal-Typen bekannt?

[Ungeprüfte: Sie könnten versuchen, vielleicht mit „% d“ Gießen dies zu verdoppeln und dann in den extra ‚guard‘ Ziffern ziehen wird, aber es wird immer noch nicht für alle Werte arbeiten]

+0

Vielen Dank für Ihre Antworten. Ich möchte den Gleitkommawert in xml speichern, zu diesem Zweck konvertiere ich in eine Zeichenkette. Ich möchte den genauen Float-Wert zurücklesen. Mein Problem ist, wenn ich von Float zu String umwandele, verliere ich die Genauigkeit. Ich möchte die genauen Genauigkeiten zurück. Wie macht man das? –

+0

Das sagt, was Sie tun, aber nicht warum. –

+0

Ich lese Float-Wert vom Gerät.Nach einiger Zeit werde ich den gleichen Wert für das Gerät schreiben.Wenn sich die Genauigkeit ändert, wird das Gerät es nicht akzeptieren. –

0

Vielleicht verwenden Sie fprintf() (von), um Ihren Float in einen String zu konvertieren. Aber die Präzision könnte sofort nach der Affektierung verloren gehen, weil 'flaot' und 'double' eine begrenzte Genauigkeit haben. Jemand muss das bestätigen.

+0

Soll das überhaupt eine Antwort sein? – Tara

0

Der beste Weg ist, seine Binärdarstellung zu speichern, wie von @pgm vorgeschlagen. speichert es jedoch konnte man auch in Dezimalschreibweise, aber unter Verwendung von Zeit-Notation, wie:

23.5095446(1545855463) 

Auf diese Weise sie irgendwie „lossless“ gespeichert werden könnten, aber es wird sehr vorsichtig Codierung erfordern.

7

C99 unterstützt das %a Format in printf, das ermöglicht, den Inhalt eines Doppels ohne Genauigkeitsverlust auszugeben.

+1

+1 Und das Gegenteil ist einfach "% lf" in 'scanf'. – pmg

2

Die Anzahl der (dezimal) Ziffern Sie müssen eindeutig jede float vertreten ist definitions std::numeric_limits<float>::digits10. Das Format float kann nicht zwischen 0.0 und 0.0000 unterscheiden, daher ist diese Konstante der Höchstwert, den Sie jemals brauchen werden.

Nun, beachten Sie, dass ich eindeutig sagte. Dies ist nicht genau Es bedeutet, dass wenn Sie zwei verschiedene Binärwerte schreiben, erhalten Sie zwei verschiedene Dezimaldarstellungen. Es bedeutet auch, dass wenn Sie eine solche Dezimaldarstellung zurücklesen, diese nicht mit anderen Werten verwechselt werden kann und Sie daher genau den gleichen Binärwert erhalten, den Sie zuvor hatten. Normalerweise sind diese beiden Garantien ausreichend.

0

Speichern Sie es, damit Sie es später erneut lesen und als Float verwenden können? Oder interessiert es dich, was die Schnur sagt? Wie andere gesagt haben, müssen Sie die binäre Darstellung anstelle der base10 schreiben. Oder man kann ein wenig schwierig sein und tut so etwas wie dies

float f=23.345466467 
int i=*(int*)&f; //re-interpret the bits in f as an int 
cout << i; 

und liest es

int i; 
cin >> i; 
float f=*(float&)&i; 

[Standard disclamer über Portabilität und dafür sorgen, dass int und float die gleiche Größe auf Ihrer Plattform ist. ]

Auf diese Weise können Sie den Wert ausgeben und ihn ohne Genauigkeitsverlust wieder einlesen. Aber es ist nicht menschlich lesbar, wenn es gespeichert wird.

2

Andere haben bereits kommentiert, dass 23,345466467 nicht als Schwimmer vorhanden ist, aber wenn Ihr Ziel nur Round-Trip-Umwandlung von Gleitkommazahlen ist, die ihren Wert existieren leicht ohne versehentlich zu ändern, können Sie entweder snprintf und strtod mit mindestens verwenden bei DECIMAL_DIG Orte (POSIX, aber nicht einfach ISO C, garantiert diesen Umlauf genau) oder drucken Sie den Float in Hex statt Dezimal. C99 hat den Formatbezeichner %a für das Drucken von Schwimmern in Hex, aber wenn Sie sich nicht auf C99 verlassen können, ist es einfach, Ihr eigenes zu schreiben. Anders als bei Dezimalzahlen funktioniert der naive Algorithmus zum Drucken von Hex-Floats gut. Es geht so:

  1. Maßstab durch eine Potenz von 2 0x8 <= val < 0x10 den Wert im Bereich zu setzen. Diese Potenz von 2 wird zum Exponenten in Ihrem Ergebnis.
  2. Entfernen Sie wiederholt den ganzzahligen Teil von val und multiplizieren Sie mit 0x10, um die Ausgangsziffern zu erhalten.
  3. Wenn val 0 erreicht, sind Sie fertig.

Die Konvertierung in die entgegengesetzte Richtung ist ebenfalls einfach.

5

Siehe die nette ausführliche Diskussion in http://randomascii.wordpress.com/2012/03/08/float-precisionfrom-zero-to-100-digits-2/.

Die kurze Antwort ist, dass die minimale Genauigkeit ist folgende:

printf("%1.8e", d); // Round-trippable float, always with an exponent 
printf("%.9g", d); // Round-trippable float, shortest possible 
printf("%1.16e", d); // Round-trippable double, always with an exponent 
printf("%.17g", d); // Round-trippable double, shortest possible 

oder äquivalent mit einem std::ostream& os:

os << scientific << setprecision(8) << d; // float; always with an exponent 
os << defaultfloat << setprecision(9) << d; // float; shortest possible 
os << scientific << setprecision(16) << d; // double; always with an exponent 
os << defaultfloat << setprecision(17) << d; // double; shortest possible 
+0

Siehe auch diesen Beitrag für weitere Details: http://randomascii.wordpress.com/2013/02/07/float-precision-revisited-nine-digit-float-portability/ –

-1

In C#, verwenden Sie die "R" numerische Formatierungszeichenfolge, wie in:

float x = 23.345466467f; 
string str = x.ToString("R"); 

Beachten Sie, dass "R" die Abkürzung für "Round-trip" ist. Weitere Informationen unter MSDN.

+0

-1, für eine völlig andere Antwort Sprache. Hilft dem OP überhaupt nicht. – MSalters

+0

Vielleicht nicht, aber es könnte jemand anderem helfen, der auf diese Seite googelt und nach einer C# -Antwort sucht (wie ich es getan habe). Mir war klar, dass das OP C/C++ wollte, also machte ich klar, in welcher Sprache ich sprach. – yoyo

Verwandte Themen