2016-07-20 12 views
0

Ich lese Werte aus einer Textdatei und konvertiere sie in Doppel, dann muss ich diese Werte auf dem Bildschirm drucken, und sie sollten genauso aussehen wie in der Textdatei.Erhalte die Genauigkeit einer Zeichenkettennummer

Derzeit bin ich mit max Präzision beim Drucken, und ich könnte Ergebnisse wie diese:

Textwert: 8.994279313857e-317 gedruckt Wert: 8.99427931385706e-317

Jede Textdatei kann unterschiedliche Genauigkeit haben, oder sogar unterschiedliche Genauigkeit für verschiedene Werte (in der gleichen Textdatei), und ich kann diese Werte nicht als Zeichenfolgen für Speicherinteressen speichern.

Mein Gedanke ist es, sie als Doppel mit einem anderen unsigned Int für Präzision zu speichern, gibt es eine Möglichkeit, die Präzision aus einer Zeichenfolge Nummer zu bekommen?

+0

* "Ich lese Werte aus einer Textdatei und konvertiere sie in Doppel, dann muss ich diese Werte auf dem Bildschirm drucken, und sie sollten genauso aussehen wie in der Textdatei." * - This erfordert, dass Sie Ihre Zahlen als Zeichenfolgen speichern. Unter der Annahme, dass Ihre Textdatei Basis-10-Nummern speichert und Gleitkommazahlen als Base-2 auf Ihrem System gespeichert sind, können Sie in Ihrer Zielcodierung niemals die Quellnummer darstellen. Sie müssen die Fäden in der Hand halten. Dies ist alles nur vorzeitige Optimierung, also verschrotten Sie es und speichern Sie die Zahlen als Zeichenfolgen. Es ist ** das ** einfach, wirklich. – IInspectable

+0

Sie könnten boost.multiprecision vielleicht versuchen. Die Speicherung als String ist jedoch die einfachste Lösung. –

+0

Der Fall ist, dass wir minimalen Speicher verwenden müssen, um die Anforderungen zu erfüllen, also Strings werden einfach nicht tun: S – nancyheidilee

Antwort

0

Sie können Ihren Kuchen nicht haben und essen es auch! :)

Ich meine, wollen Sie die genaue Darstellung einer Zeichenkette in einer Reihe, ohne die Kosten in Bezug auf Speicher zu zahlen (um nur die Zeichenfolge zu speichern *).

Also in diesem Fall das Beste, was Sie tun könnten, ist eine long double verwenden, wissen Sie, die L wir am Ende der numerischen Konstanten anhängen. Das hat natürlich auch seine Grenzen (da unser Computer auch Grenzen hat). Darüber hinaus, was für eine Verschwendung von Speicherplatz (und Bearbeitungszeit) würde es sein, eine long double für Zahlen, die nicht brauchen, zu verwenden, da Sie sagen, dass die Genauigkeiten, die Sie erfüllen werden, nicht behoben sind. So konnten Sie das tun mit diesem Code (freundlicherweise zusammengebaut, indem this und this Antworten und die std::numeric limits):

#include <fstream> 
#include <vector> 
#include <cstdlib> 
#include <iostream> 
#include <limits> 

typedef std::numeric_limits<double> dbl; 

int main() { 
    std::ifstream ifile("example.txt", std::ios::in); 
    std::vector<long double> scores; 

    //check to see that the file was opened correctly: 
    if (!ifile.is_open()) { 
     std::cerr << "There was a problem opening the input file!\n"; 
     exit(1);//exit or do additional error checking 
    } 

    long double num = 0.0; 
    //keep storing values from the text file so long as data exists: 
    while (ifile >> num) { 
     scores.push_back(num); 
    } 

    std::cout.precision(dbl::max_digits10); // you can print more digits if you like, you won't the exact representation obviously 
    //verify that the scores were stored correctly: 
    for (int i = 0; i < scores.size(); ++i) { 
     std::cout << std::fixed << scores[i] << std::endl; 
    } 

    return 0; 
} 

die auf meinem Rechner gibt:

C02QT2UBFVH6-lm:~ gsamaras$ cat example.txt 
3.12345678912345678912345678 2.79 
C02QT2UBFVH6-lm:~ gsamaras$ g++ -Wall main.cpp 
C02QT2UBFVH6-lm:~ gsamaras$ ./a.out 
3.12345678912345679 
2.79000000000000000 

Wenn Sie möchten, um noch weiter zu gehen, dann benutze GMP, was "eine freie Bibliothek für beliebige Präzisionsarithmetik" ist. Natürlich wird dies nicht kostenlos in Bezug auf die Speicherauslastung und Verarbeitungszeit kommen, so sollten Sie wirklich zweimal überlegen vor der Verwendung!


* ich das Gefühl, dass Sie ein Opfer der vorzeitigen Optimierung sind. Wenn ich Sie wäre, würde ich einfach die Strings speichern und sehen, wie das geht, oder besser noch einen numerischen Datentyp verwenden, wodurch ich etwas an Präzision einbüße, was Ihr Leben viel einfacher macht. Wenn das Projekt fertig ist, sehen Sie, welche Ergebnisse Sie erhalten und ob die erreichte Präzision "Ihrem Chef" gefällt. Wenn nicht, verwenden Sie Zeichenfolgen (oder ).

+0

'long double' garantiert nicht eine höhere Genauigkeit oder einen größeren Bereich als ein' double'. Die letzte Version von Visual Studio zur Unterstützung einer 80-Bit-Gleitkommadarstellung war Visual Studio 6 SP6. Heute verwenden beide Fließkommatypen die gleiche Darstellung (siehe [Grundtypen (C++)] (https://msdn.microsoft.com/en-us/library/cc953fe1.aspx)), wenn Sie Visual Studio verwenden. – IInspectable

+0

@Intensible sicher, in Visual Studio! :) – gsamaras

0

Der richtige Weg ist es, irgendeine Klasse zu verwenden, die einen numerischen Wert getreu darstellt. Um solche Werte darzustellen, können Sie die Ganzzahl mit beliebiger Genauigkeit und Skalierungsfaktor verwenden.

#include <boost/multiprecision/cpp_int.hpp> 

// numeric = value/pow(10, scale) 
struct numeric { 
    /// arbitrary precision integer 
    boost::multiprecision::cpp_int value; 
    /// point position 
    int scale; 
}; 
// for example, 10.1 can be represented with the numeric class exactlty in difference to double : 
numeric n{101, 1}; // 101/pow(10, 1) 

drucken solche Nummer können Sie Hilfsfunktion verwenden, die Objekte der numerischen Klasse konvertieren std :: string: Zum Beispiel kann es wie folgt definiert werden

std::string to_string(const numeric& n) const 
{ 
    if (n.value.is_zero() && n.scale <= 0) 
    return "0"; 
    bool neg = n.value < 0; 
    std::string r; 
    { 
    std::ostringstream s; 
    s << (neg ? -n.value : n.value); 
    s.str().swap(r); 
    } 
    if (n.scale > 0) { 
    if (n.scale >= r.length()) { 
     r = std::string(n.scale - r.length() + 1, '0') + r; 
    } 
    r.insert(r.length() - n.scale, 1, '.'); 
    if (neg) 
     r = '-' + r; 
    } 
    else if (n.scale < 0) { 
    if (neg) 
     r = '-' + r; 
    r += std::string(-n.scale, '0'); 
    } 
    else { 
    if (neg) 
     r = '-' + r; 
    } 
    return std::move(r); 
} 

zu konstruieren, die numerisches Objekt von std :: string Sie können Punktposition finden (das ist die Skala des numerischen), entfernen Punkt und init cpp_int mit dem gelöschten von einem Punkt string.

+0

* "Um das numerische Objekt von std :: string zu erstellen, können Sie ..." * - Nun, nein, es ist sicherlich nicht ** das ** einfach. Sie müssen immer noch für +/- Zeichen (und bewahren Sie diese Informationen), Tausendertrennzeichen oder wissenschaftliche Notation (z. B. "101e-1"). Und mit all den zusätzlichen Informationen, die gespeichert werden, werden die Einsparungen so gering, dass es schwer zu rechtfertigen ist, die Strings nicht einfach zu speichern. – IInspectable

+0

@Inspectable: ok, aber es ist nicht so schwer mit Regex zu implementieren. – AnatolyS

+0

* "Es ist nicht so schwer" * - Ich glaube dir, sobald du einen regulären Ausdruck gefunden hast, funktioniert das zuverlässig.Aber das alles fehlt der Punkt, den ich versuchte zu machen: Wenn Sie alle Informationen speichern möchten, die notwendig sind, um die ursprüngliche Formatierung eines Fließkomma-Literals (zusätzlich zu einer Binärdarstellung) zu reproduzieren, ist es wahrscheinlich effizienter, die Zeichenkette einfach zu speichern . – IInspectable

Verwandte Themen