2015-09-03 10 views
14

ich zur Zeit über diese staunte:Precision Unterschied beim Drucken Python und C++ verdoppelt

C++ 11

#include <iostream> 
#include <iomanip> 
#include <limits> 

int main() 
{ 
    double d = 1.305195828773568; 
    std::cout << std::setprecision(std::numeric_limits<double>::max_digits10) << d << std::endl; 
    // Prints 1.3051958287735681 
} 

Python

>>> repr(1.305195828773568) 
'1.305195828773568' 

Was ist los, warum die extra 1 in C++?

Bisher dachte ich, dass C++ und Python die gleichen 64-Bit-IEEE-Doubles unter der Haube verwenden; Beide Formatierungsfunktionen sollen die volle Präzision drucken.

+1

Beachten Sie, dass * die * Eigenschaft von 'repr' ist:' eval (repr (x)) == x '** nicht **, dass Zahlen mit allen Dezimalziffern gedruckt werden. Wenn Sie eine Genauigkeit von 'k' wünschen, sollten Sie eine korrekte Formatierungsfunktion verwenden. – Bakuriu

Antwort

2

aus einer Antwort auf this question Genommen:

IEEE 754 Gleitkomma wird binär gemacht. Es gibt keine exakte Umwandlung von einer gegebenen Anzahl von Bits zu einer gegebenen Anzahl von Dezimalziffern. 3 Bits können Werte von 0 bis 7 enthalten, und 4 Bits können Werte von 0 bis 15 enthalten. Ein Wert von 0 bis 9 benötigt ungefähr 3,5 Bits, aber das ist auch nicht genau.

Eine IEEE 754-Nummer mit doppelter Genauigkeit belegt 64 Bit. Davon sind 52 Bits dem Signifikanden zugeordnet (der Rest ist ein Vorzeichenbit und ein Exponent). Da der Signifikand (normalerweise) normalisiert ist, gibt es ein impliziertes 53. Bit.

Jetzt 53 Bits und etwa 3,5 Bits pro Ziffer gegeben, gibt uns einfache Division 15.1429 Stellen der Genauigkeit. Aber denken Sie daran, dass 3,5 Bits pro Dezimalziffer nur eine Annäherung, keine vollkommen genaue Antwort ist.

Dieses seltsame .1429 nach den 15 Stellen Sie wahrscheinlich zur Verfügung gestellt ist der Schuldige des addierten 1.

Für das, was es wert ist, Python hat dies auf ihrer Website geschrieben:

Historisch gesehen, die Python-Eingabeaufforderung und integrierte repr() Funktion würde die mit 17 signifikanten Ziffern wählen, 0.10000000000000001. Beginnend mit Python 3.1 kann Python (auf den meisten Systemen) nun den kürzesten auswählen und einfach 0.1 anzeigen.

10

Sie können Python zwingen, die 1 als auch (und viele mehr der folgenden Ziffern) zu drucken:

print('{:.16f}'.format(1.305195828773568)) 
# -> 1.3051958287735681 

von https://docs.python.org/2/tutorial/floatingpoint.html:

>>> 7205759403792794 * 10**30 // 2**56 
100000000000000005551115123125L 

In Versionen vor Python 2.7 und Python 3.1 rundete Python diesen Wert auf 17 signifikante Stellen ab und gab '0.10000000000000001'. In aktuellen Versionen, Python zeigt einen Wert auf der Grundlage der kürzesten Dezimalbruch, der korrekt auf den wahren Binärwert, aufrundet Ergebnis einfach in '0,1'.

"Druck die volle Präzision" ist schwer zu tun: Was ist die volle Präzision?die Darstellung von floats ist binär; nur Bruchteile von Zweierpotenzen können genau dargestellt werden (bis zur vollen Genauigkeit); die meisten Dezimalbrüche können nicht genau in der Basis 2 dargestellt werden.

aber das float im Speicher wird für python und C++ dasselbe sein; Es ist nur die Zeichenfolgendarstellung, die sich unterscheidet.

+0

"die meisten Dezimalbrüche können nicht genau in Basis 2 dargestellt werden" - ja, aber umgekehrt ist nicht wahr. Alle binären Brüche sind in Dezimal darstellbar. Es sollte also möglich sein, eine genaue Dezimaldarstellung zu erhalten. – n0rd

+0

@ n0rd Korrigieren. Die einzigen Nachteile sind, dass es eine ziemlich lange Darstellung und wahrscheinlich nicht repräsentativ für die tatsächliche Eingabe wäre, von der der binäre Gleitkomma erhalten wurde. –

+2

Der genaue Wert der nächsten IEEE 64-Bit-Binär-Gleitkommazahl ist 1.3051958287735681008001620284630917012691497802734375 - definitiv nicht repräsentativ für die tatsächliche Eingabe. –

3

Wenn das Format mit Festkomma-Notation endet, gibt precision() die Anzahl der Nachkommastellen an. Da es in Ihrem Beispiel zusätzliche nicht-gebrochene Ziffern gibt, wird eine mehr als die, die sicher dargestellt werden kann, erstellt.

Bei Verwendung der wissenschaftlichen Notation wird die Gesamtzahl der Ziffern gezählt und Sie erhalten die gleichen Ziffern wie das Original (plus natürlich einen Exponenten). Die C- und C++ - Optionen zum Formatieren von Gleitkommazahlen sind eigentlich ziemlich schlecht. Insbesondere gibt es keine Option, die es dem Formatierer erlaubt, die geeignete Anzahl von Stellen zu bestimmen, obwohl der zugrundeliegende Algorithmus diese tatsächlich bestimmen kann.