2015-09-03 15 views
14

Attualmente sto meravigliandomi su questo:differenza di precisione per la stampa di Python e C++ raddoppia

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' 

Che cosa sta succedendo, perché il 1 extra in C++?

Finora ho pensato che C++ e Python usassero gli stessi doppi IEEE a 64 bit sotto il cofano; entrambe le funzioni di formattazione dovrebbero stampare la massima precisione.

+1

Si noti che * la proprietà * di 'repr' è:' eval (repr (x)) == x' ** not ** che i numeri vengono stampati con tutte le cifre decimali. Se si desidera una precisione delle cifre decimali 'k', è necessario utilizzare una funzione di formattazione corretta. – Bakuriu

risposta

2

tratto da una risposta a this question:

IEEE 754 in virgola mobile è fatto in binario. Non esiste una conversione esatta da un determinato numero di bit a un determinato numero di cifre decimali. 3 bit possono contenere valori da 0 a 7 e 4 bit possono contenere valori da 0 a 15. Un valore compreso tra 0 e 9 richiede circa 3,5 bit, ma non è esatto neanche uno.

Un numero di precisione doppia IEEE 754 occupa 64 bit. Di questo, 52 bit sono dedicati al significato (il resto è un bit ed esponente di segno). Dal momento che il significato e (di solito) normalizzato, c'è un implicito 53 ° bit.

Ora, con 53 bit e circa 3,5 bit per cifra, la divisione semplice fornisce 15,1429 cifre di precisione. Ma ricorda, quel 3,5 bit per cifra decimale è solo un'approssimazione, non una risposta perfettamente accurata.

Questo strano .1429 dopo le 15 cifre che hai fornito è probabilmente il colpevole del aggiunto 1.

Per quel che vale, Python ha questo scritto sul loro sito:

Storicamente, il Il prompt di Python e la funzione integrata repr() sceglierebbero quella con 17 cifre significative, 0.10000000000000001. A partire da Python 3.1, Python (sulla maggior parte dei sistemi) è ora in grado di scegliere il più breve di questi e visualizzare semplicemente 0.1.

10

è possibile forzare python per stampare il 1 nonché (e molti più dei seguenti cifre):

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

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

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

Nelle versioni precedenti a Python 2.7 e Python 3.1, Python ha arrotondato questo valore a 17 cifre significative, fornendo "0,10000000000000001". Nelle versioni correnti di , Python visualizza un valore basato sulla più breve frazione decimale che ritorna correttamente al valore binario vero, risultante semplicemente in "0.1".

"stampare la massima precisione" è difficile da fare: qual è la precisione completa?la rappresentazione dei float è binaria; solo le frazioni di poteri di 2 possono essere rappresentate esattamente (a piena precisione); la maggior parte delle frazioni decimali non può essere rappresentata esattamente nella base 2.

ma il float nella memoria sarà lo stesso per python e C++; è solo la rappresentazione della stringa che differisce.

+0

"la maggior parte delle frazioni decimali non può essere rappresentata esattamente nella base 2" - sì, ma il contrario non è vero. Tutte le frazioni binarie sono rappresentabili in decimale. Quindi dovrebbe essere possibile ottenere una rappresentazione decimale esatta. – n0rd

+0

@ n0rd corretto. Gli unici svantaggi sono che sarebbe una rappresentazione piuttosto lunga e probabilmente non rappresentativa dell'effettivo input da cui è stato ottenuto il float binario. –

+2

Il valore esatto del numero in virgola mobile binario IEEE a 64 bit più vicino è 1.3051958287735681008001620284630917012691497802734375 - sicuramente non rappresentativo dell'input effettivo. –

3

Quando il formato termina utilizzando la notazione a virgola fissa, precision() specifica il numero di cifre frazionarie. Poiché nel tuo esempio sono presenti cifre non frazionarie aggiuntive, viene creato un numero maggiore di quelli che possono essere rappresentati in modo sicuro.

Quando si utilizza la notazione scientifica, viene contato il numero totale di cifre e si otterranno le stesse cifre dell'originale (più un esponente, ovviamente). Le opzioni C e C++ per la formattazione di numeri in virgola mobile sono in effetti piuttosto negative. In particolare, non vi è alcuna opzione che permetta al formattatore di decidere il numero appropriato di cifre sebbene l'algoritmo sottostante possa effettivamente determinarle.

Problemi correlati