Więc otrzymałem odpowiedź na moje ostatnie pytanie (nie wiem, dlaczego o tym nie pomyślałem). Drukowałem double
użycie, cout
które zaokrągliło się, gdy się nie spodziewałem. Jak mogę sprawić, by cout
wydruk był w double
pełni precyzyjny?
Więc otrzymałem odpowiedź na moje ostatnie pytanie (nie wiem, dlaczego o tym nie pomyślałem). Drukowałem double
użycie, cout
które zaokrągliło się, gdy się nie spodziewałem. Jak mogę sprawić, by cout
wydruk był w double
pełni precyzyjny?
Odpowiedzi:
Możesz ustawić precyzję bezpośrednio na std::cout
i użyć specyfikatora std::fixed
formatu.
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>
1
do std::numeric_limits<double>::digits10
?
max_digits10
, a nie dowolnedigits10+2
. W przeciwnym razie, w przypadku float
, long double
, boost::multiprecision::float128
to nie uda, ponieważ należałoby +3
zamiast +2
.
Sposób iostreams jest trochę niezgrabny. Wolę używać, boost::lexical_cast
ponieważ 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 double
jest przechowywana przy użyciu reprezentacji podstawy 2, a podstawa 2 nie może reprezentować czegoś tak trywialnego jak 1.1
dokł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 „ double
a”, union
a 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.0000000000005
nie 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ć
double
wartość z pełną precyzją za pomocą cout?
Użyj hexfloat
lub
użyj scientific
i 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 double
jest 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
fixed
lub scientific
?A double
jest typem zmiennoprzecinkowym , a nie stałym .
Czy nie używać std::fixed
jako że nie drukować małe double
jak bynajmniej 0.000...000
. W przypadku dużych double
drukuje 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::scientific
któ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 double
Zakodowane 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 N
cyframi znaczącymi, liczba kombinacji [1,0 ... 10,0) wynosi 9/10 * 10 N. .
Bez względu na N
wybraną (precyzję) double
tekst nie będzie mapowany jeden na jeden między tekstem dziesiętnym a dziesiętnym. Jeśli N
zostanie wybrana wartość stała , czasami będzie ona nieco bardziej lub mniej niż rzeczywiście potrzebna dla niektórych double
wartoś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 N
so podczas konwersji z double
tekstu-tekstu, aby uzyskać ten sam tekst dla wszystkich double
.
std::cout << dbl::digits10 << '\n';
// Typical output
15
b) Użyj N
so podczas konwersji z double
-tekstu - double
my osiągamy to samo double
dla wszystkich double
.
// C++11
std::cout << dbl::max_digits10 << '\n';
// Typical output
17
Gdy max_digits10
nie jest dostępny, należy pamiętać, że ze względu na atrybuty base 2 i base 10 digits10 + 2 <= max_digits10 <= digits10 + 3
możemy użyćdigits10 + 3
aby zapewnić wydrukowanie wystarczającej liczby cyfr dziesiętnych.
c) Użyj N
zmiennej 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-ish
w 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_digits10
wię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 scientific
okreś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 printf
mogą 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;
,fixed
daje mi0.000000000000000
iscientific
wychodzi6.626069570000000e-34
.