2015-09-03 11 views
14

Jestem obecnie zachwycając się nad tym:Precision różnica przy drukowaniu Python i C++ podwaja

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' 

Co się dzieje, dlaczego dodatkowe 1 w C++?

Do tej pory myślałem, że C++ i Python używają tego samego 64-bitowego IEEE pod maską; obie funkcje formatowania mają wydrukować pełną precyzję.

+1

Należy pamiętać, że * właściwością * repr jest: 'eval (repr (x)) == x' ** nie ** że cyfry są drukowane ze wszystkimi cyframi dziesiętnymi. Jeśli chcesz uzyskać dokładność cyfr dziesiętnych "k", powinieneś użyć odpowiedniej funkcji formatowania. – Bakuriu

Odpowiedz

2

Zrobione z odpowiedzią na this question:

IEEE 754 zmiennoprzecinkowych odbywa się w systemie binarnym. Nie ma dokładnej konwersji z określonej liczby bitów na określoną liczbę cyfr dziesiętnych. 3 bity mogą zawierać wartości od 0 do 7, a 4 bity mogą zawierać wartości od 0 do 15. Wartość od 0 do 9 zajmuje mniej więcej 3,5 bity, ale to też nie jest dokładne.

Numer podwójnej precyzji IEEE 754 zajmuje 64 bity. Z tego 52 bitów jest dedykowanych dla significand (reszta to bit znaku i wykładnik). Ponieważ significand jest (zwykle) znormalizowany, istnieje domniemany 53. bit.

Teraz, biorąc pod uwagę 53 bity i mniej więcej 3,5 bity na cyfrę, prosty podział daje nam 15.1429 cyfr dokładności. Należy jednak pamiętać, że 3,5 bity na cyfrę dziesiętną są jedynie przybliżeniem, a nie dokładną odpowiedzią.

To dziwne .1429 po 15 cyfr ty przewidziane jest prawdopodobnie sprawcą dodanego 1.

Na co warto, Python jest to napisane na ich stronie:

Historycznie Python prompt i wbudowana funkcja repr() wybierze tę z 17 cyframi znaczącymi, 0.10000000000000001. Począwszy od wersji Python 3.1, Python (w większości systemów) jest teraz w stanie wybrać najkrótszy z nich i po prostu wyświetla 0.1.

10

można zmusić Pythona do wydrukowania 1, jak również (i wiele więcej z następujących cyfr):

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

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

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

W wersjach przed Pythonie 2.7 i Python 3.1, Python zaokrągla tę wartość do 17 cyfr znaczących, podając "0.10000000000000001". W aktualnych wersjach , Python wyświetla wartość na podstawie najkrótszej ułamka dziesiętnego , która zaokrągla poprawnie z powrotem do prawdziwej wartości binarnej, , co daje wynik "0,1".

"Drukowanie pełnej precyzji" jest trudne: jaka jest pełna precyzja?reprezentacja float jest binarna; tylko frakcje mocy 2 mogą być dokładnie odwzorowane (z pełną precyzją); większość ułamków dziesiętnych nie może być dokładnie odwzorowana w podstawie 2.

, ale zmienna w pamięci będzie taka sama dla Pythona i C++; jest to tylko reprezentacja ciągów, która różni się.

+0

"większość ułamków dziesiętnych nie może być przedstawiona dokładnie w podstawie 2" - tak, ale odwrócenie nie jest prawdą. Wszystkie ułamki binarne są reprezentowane dziesiętnie. Powinno być możliwe uzyskanie dokładnej reprezentacji dziesiętnej. – n0rd

+0

@ n0rd Prawidłowe. Jedynym minusem jest to, że byłaby to raczej długa reprezentacja i prawdopodobnie nie reprezentowałaby rzeczywistego sygnału wejściowego, z którego uzyskano binarny zmienny. –

+2

Dokładna wartość najbliższej 64-bitowej liczby zmiennoprzecinkowej IEEE wynosi 1,3051958287735681008001620284630917012691497802734375 - zdecydowanie nie jest reprezentatywna dla rzeczywistego wejścia. –

3

Po zakończeniu formatowania za pomocą notacji o stałym punkcie, precision() określa liczbę cyfr ułamkowych. Ponieważ w twoim przykładzie są dodatkowe nie ułamkowe cyfry, tworzony jest więcej niż te, które można bezpiecznie przedstawić.

Podczas korzystania z notacji naukowej liczona jest całkowita liczba cyfr, a otrzymasz te same cyfry co oryginał (i oczywiście wykładnik). Opcje C i C++ do formatowania liczb zmiennoprzecinkowych są w rzeczywistości dość złe. W szczególności nie ma opcji, która pozwala konstruktorowi decydować o odpowiedniej liczbie cyfr, chociaż algorytm bazowy może je faktycznie określić.

Powiązane problemy