Więc otrzymałem odpowiedź na moje ostatnie pytanie (nie wiem, dlaczego o tym nie pomyślałem). Drukowałem doubleużycie, coutktóre zaokrągliło się, gdy się nie spodziewałem. Jak mogę sprawić, by coutwydruk był w doublepełni precyzyjny?
Więc otrzymałem odpowiedź na moje ostatnie pytanie (nie wiem, dlaczego o tym nie pomyślałem). Drukowałem doubleużycie, coutktóre zaokrągliło się, gdy się nie spodziewałem. Jak mogę sprawić, by coutwydruk był w doublepełni precyzyjny?
Odpowiedzi:
Możesz ustawić precyzję bezpośrednio na std::couti użyć specyfikatora std::fixedformatu.
double d = 3.14159265358979;
cout.precision(17);
cout << "Pi: " << fixed << d << endl;
Możesz #include <limits>uzyskać maksymalną precyzję liczby zmiennoprzecinkowej lub podwójnej.
#include <limits>
typedef std::numeric_limits< double > dbl;
double d = 3.14159265358979;
cout.precision(dbl::max_digits10);
cout << "Pi: " << d << endl;
cout.precision(numeric_limits<double>::digits10 + 2);dostaję tylko 16 ....
max_digits10 to samo. Naprawiono odpowiedź, aby to odzwierciedlić.
Posługiwać się std::setprecision :
std::cout << std::setprecision (15) << 3.14159265358979 << std::endl;
std::setprecision (17)podwójny, zobacz komentarze do odpowiedzi @Bill The Lizard.
Oto czego bym użył:
std::cout << std::setprecision (std::numeric_limits<double>::digits10 + 1)
<< 3.14159265358979
<< std::endl;
Zasadniczo pakiet limitów ma cechy wszystkich typów wbudowanych.
Jedną z cech liczb zmiennoprzecinkowych (liczba zmiennoprzecinkowa / podwójna / długa podwójna) jest atrybut digits10. To określa dokładność (nie pamiętam dokładnej terminologii) liczby zmiennoprzecinkowej w podstawie 10.
Zobacz: http://www.cplusplus.com/reference/std/limits/numeric_limits.html
Szczegółowe informacje na temat innych atrybutów.
std::setprecision(): #include <iomanip>
std::numeric_limits<double>zamiastnumberic_limits<double>
1do std::numeric_limits<double>::digits10?
max_digits10, a nie dowolnedigits10+2 . W przeciwnym razie, w przypadku float, long double, boost::multiprecision::float128to nie uda, ponieważ należałoby +3zamiast +2.
Sposób iostreams jest trochę niezgrabny. Wolę używać, boost::lexical_castponieważ oblicza dla mnie odpowiednią precyzję. I to też jest szybkie .
#include <string>
#include <boost/lexical_cast.hpp>
using boost::lexical_cast;
using std::string;
double d = 3.14159265358979;
cout << "Pi: " << lexical_cast<string>(d) << endl;
Wynik:
Pi: 3,14159265358979
Przez pełną precyzję zakładam, że oznacza wystarczającą precyzję, aby pokazać najlepsze przybliżenie do zamierzonej wartości, ale należy zauważyć, że doublejest przechowywana przy użyciu reprezentacji podstawy 2, a podstawa 2 nie może reprezentować czegoś tak trywialnego jak 1.1dokładnie. Jedynym sposobem na uzyskanie pełnej precyzji rzeczywistego podwójnego (bez BŁĘDU WYŁĄCZENIA ZAOKRĄGLENIA) jest wydrukowanie bitów binarnych (lub hex nybbles). Jednym ze sposobów jest zapisanie wartości „ doublea”, uniona następnie wydrukowanie wartości całkowitej bitów.
union {
double d;
uint64_t u64;
} x;
x.d = 1.1;
std::cout << std::hex << x.u64;
To da ci 100% dokładną precyzję podwójnego ... i będzie całkowicie nieczytelny, ponieważ ludzie nie potrafią odczytać podwójnego formatu IEEE! Wikipedia dobrze napisała, jak interpretować binarne bity.
W nowszym C ++ możesz to zrobić
std::cout << std::hexfloat << 1.1;
Oto jak wyświetlić podwójnie z pełną precyzją:
double d = 100.0000000000005;
int precision = std::numeric_limits<double>::max_digits10;
std::cout << std::setprecision(precision) << d << std::endl;
Wyświetla to:
100,0000000000005
max_digits10 to liczba cyfr niezbędnych do jednoznacznego przedstawienia wszystkich wyraźnych podwójnych wartości. max_digits10 reprezentuje liczbę cyfr przed i po przecinku.
Nie używaj set_precision (max_digits10) ze std :: fixed.
W stałej notacji set_precision () ustawia liczbę cyfr tylko po przecinku. Jest to niepoprawne, ponieważ max_digits10 reprezentuje liczbę cyfr przed kropką dziesiętną i po niej.
double d = 100.0000000000005;
int precision = std::numeric_limits<double>::max_digits10;
std::cout << std::fixed << std::setprecision(precision) << d << std::endl;
Wyświetla niepoprawny wynik:
100,00000000000049738
Uwaga: Wymagane pliki nagłówka
#include <iomanip>
#include <limits>
100.0000000000005nie jest reprezentowane dokładnie jako double. (Może się wydawać, że tak powinno być, ale tak nie jest, ponieważ ulega normalizacji , tj. Reprezentacji binarnej). Aby to zobaczyć, spróbuj: 100.0000000000005 - 100. Dostajemy 4.973799150320701e-13.
Jak wydrukować
doublewartość z pełną precyzją za pomocą cout?
Użyj hexfloatlub
użyj scientifici ustaw dokładność
std::cout.precision(std::numeric_limits<double>::max_digits10 - 1);
std::cout << std::scientific << 1.0/7.0 << '\n';
// C++11 Typical output
1.4285714285714285e-01
Zbyt wiele odpowiedzi dotyczy tylko jednej z 1) bazy 2) stałego / naukowego układu lub 3) precyzji. Zbyt wiele precyzyjnych odpowiedzi nie zapewnia odpowiedniej wymaganej wartości. Stąd odpowiedź na stare pytanie.
A doublejest z pewnością zakodowane przy użyciu bazy 2. Bezpośrednim podejściem w C ++ 11 jest drukowanie przy użyciu std::hexfloat.
Jeśli wyjście nie dziesiętne jest dopuszczalne, jesteśmy skończeni.
std::cout << "hexfloat: " << std::hexfloat << exp (-100) << '\n';
std::cout << "hexfloat: " << std::hexfloat << exp (+100) << '\n';
// output
hexfloat: 0x1.a8c1f14e2af5dp-145
hexfloat: 0x1.3494a9b171bf5p+144
fixedlub scientific?A doublejest typem zmiennoprzecinkowym , a nie stałym .
Czy nie używać std::fixedjako że nie drukować małe doublejak bynajmniej 0.000...000. W przypadku dużych doubledrukuje wiele cyfr, być może setki wątpliwej informatywności.
std::cout << "std::fixed: " << std::fixed << exp (-100) << '\n';
std::cout << "std::fixed: " << std::fixed << exp (+100) << '\n';
// output
std::fixed: 0.000000
std::fixed: 26881171418161356094253400435962903554686976.000000
Aby drukować z pełną precyzją, najpierw użyj, std::scientificktóry „zapisze wartości zmiennoprzecinkowe w notacji naukowej”. Zauważ, że domyślnie 6 cyfr po przecinku, niewystarczająca ilość, jest obsługiwane w następnym punkcie.
std::cout << "std::scientific: " << std::scientific << exp (-100) << '\n';
std::cout << "std::scientific: " << std::scientific << exp (+100) << '\n';
// output
std::scientific: 3.720076e-44
std::scientific: 2.688117e+43
ZA doubleZakodowane przy użyciu bazowej binarnych 2 koduje sama precyzja pomiędzy różnymi uprawnieniami od 2. Jest to często 53 bitów.
[1,0 ... 2,0) są 2 53 różne double,
[2,0 ... 4,0) są 2 53 różne double,
[4,0 ... 8,0) są 2 53 różne double,
[8,0 ... 10,0) są 2 / 8 * 2 53 różnedouble .
Jednak jeśli kod jest drukowany w systemie dziesiętnym z Ncyframi znaczącymi, liczba kombinacji [1,0 ... 10,0) wynosi 9/10 * 10 N. .
Bez względu na Nwybraną (precyzję) doubletekst nie będzie mapowany jeden na jeden między tekstem dziesiętnym a dziesiętnym. Jeśli Nzostanie wybrana wartość stała , czasami będzie ona nieco bardziej lub mniej niż rzeczywiście potrzebna dla niektórych doublewartości. Możemy popełnić błąd na zbyt małej ( a)poniżej) lub zbyt dużej ( b)poniżej).
3 kandydatów N :
a) Użyj Nso podczas konwersji z doubletekstu-tekstu, aby uzyskać ten sam tekst dla wszystkich double.
std::cout << dbl::digits10 << '\n';
// Typical output
15
b) Użyj Nso podczas konwersji z double-tekstu - doublemy osiągamy to samo doubledla wszystkich double.
// C++11
std::cout << dbl::max_digits10 << '\n';
// Typical output
17
Gdy max_digits10nie jest dostępny, należy pamiętać, że ze względu na atrybuty base 2 i base 10 digits10 + 2 <= max_digits10 <= digits10 + 3możemy użyćdigits10 + 3 aby zapewnić wydrukowanie wystarczającej liczby cyfr dziesiętnych.
c) Użyj Nzmiennej zależnej od wartości.
Może to być przydatne, gdy kod chce wyświetlać minimalny tekst ( N == 1) lub dokładną wartość wartość a double( N == 1000-ishw przypadku denorm_min). Ponieważ jednak jest to „praca” i mało prawdopodobny cel PO, zostanie on odłożony na bok.
Zwykle jest to b) używane do „wydrukowania a double wartości z pełną precyzją”. Niektóre aplikacje mogą preferować: a) błąd przy niedostarczeniu zbyt dużej ilości informacji.
Z .scientific, .precision()zestawy liczba cyfr do wydrukowania po przecinku, więc 1 + .precision()cyfry są drukowane. Kod potrzebuje max_digits10więc cyfr całkowitych.precision() jest nazywany za pomocą max_digits10 - 1.
typedef std::numeric_limits< double > dbl;
std::cout.precision(dbl::max_digits10 - 1);
std::cout << std::scientific << exp (-100) << '\n';
std::cout << std::scientific << exp (+100) << '\n';
// Typical output
3.7200759760208361e-44
2.6881171418161356e+43
//1234567890123456 17 total digits
precision()określa liczbę miejsc po przecinku dla trybu naukowego. Bez określania scientificokreśla całkowitą liczbę cyfr, z wyłączeniem wykładnika wykładniczego. Wciąż możesz uzyskać wyniki naukowe, w zależności od wartości liczbowej, ale wtedy możesz również otrzymać mniej cyfr niż podałeś. Przykład: cout.precision(3); cout << 1.7976931348623158e+308; // "1.8e+308"wyniki dla printfmogą być inne. Mylące rzeczy, o których należy pamiętać.
char buf[DBL_DECIMAL_DIG + 3 + 5]; sprintf(buf, "%.*g", DBL_DECIMAL_DIG, d);Dodatkowe znaki to: znak, kropka dziesiętna, końcowe zero, e [+ | -], 3 cyfry wykładnika ( DBL_MAX_10_EXP = 308). Stąd całkowita liczba wymaganych znaków wynosi 25.
printf("%.12f", M_PI);
% .12f oznacza zmiennoprzecinkowy, z dokładnością do 12 cyfr.
Najbardziej przenośny ...
#include <limits>
using std::numeric_limits;
...
cout.precision(numeric_limits<double>::digits10 + 1);
cout << d;
Z ostream :: precyzja (int)
cout.precision( numeric_limits<double>::digits10 + 1);
cout << M_PI << ", " << M_E << endl;
ustąpi
3.141592653589793, 2.718281828459045
Dlaczego musisz powiedzieć „+1” Nie mam pojęcia, ale dodatkowa cyfra, którą z niej wyciągasz, jest poprawna.
Spowoduje to wyświetlenie wartości do dwóch miejsc po przecinku po kropce.
#include <iostream>
#include <iomanip>
double d = 2.0;
int n = 2;
cout << fixed << setprecison(n) << d;
Zobacz tutaj: Notacja punktu stałego
Użyj stałej notacji zmiennoprzecinkowej Ustawia flagę formatu floatfield dla strumienia str na naprawioną.
Gdy zmiennoprzecinkowe jest ustawione na stałe, wartości zmiennoprzecinkowe są zapisywane przy użyciu notacji stałoprzecinkowej: wartość jest reprezentowana za pomocą dokładnie tylu cyfr w części dziesiętnej, jak określono w polu dokładności (precyzja) i bez części wykładniczej.
Ustaw precyzję dziesiętną Ustawia precyzję dziesiętną używaną do formatowania wartości zmiennoprzecinkowych operacji wyjściowych.
Jeśli znasz standard IEEE do przedstawiania liczb zmiennoprzecinkowych, wiedziałbyś, że niemożliwe jest pokazanie zmiennoprzecinkowych z pełną precyzją poza zakresem normy , to znaczy zawsze spowoduje to zaokrąglenie wartości rzeczywistej.
Najpierw musisz sprawdzić, czy wartość mieści się w zakresie , jeśli tak, to użyj:
cout << defaultfloat << d ;
Użyj domyślnej notacji zmiennoprzecinkowej Ustawia flagę formatu floatfield dla strumienia str na defaultfloat.
Gdy zmiennoprzecinkowe jest ustawione na defaultfloat, wartości zmiennoprzecinkowe są zapisywane przy użyciu domyślnej notacji: reprezentacja używa tyle znaczących cyfr, ile potrzeba, aż do precyzji dziesiętnej (precyzji) strumienia, licząc obie cyfry przed i po przecinku (jeśli występują) ).
Jest to również domyślne zachowanie cout, co oznacza, że nie używasz go jawnie.
fixed? Zdouble h = 6.62606957e-34;,fixeddaje mi0.000000000000000iscientificwychodzi6.626069570000000e-34.