Então, eu recebi a resposta para minha última pergunta (não sei por que não pensei nisso). Eu estava imprimindo um double
uso cout
que era arredondado quando não esperava. Como faço para cout
imprimir double
usando precisão total?
Então, eu recebi a resposta para minha última pergunta (não sei por que não pensei nisso). Eu estava imprimindo um double
uso cout
que era arredondado quando não esperava. Como faço para cout
imprimir double
usando precisão total?
Respostas:
Você pode definir a precisão diretamente std::cout
e usar o std::fixed
especificador de formato.
double d = 3.14159265358979;
cout.precision(17);
cout << "Pi: " << fixed << d << endl;
Você pode #include <limits>
obter a precisão máxima de um flutuador ou duplo.
#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);
só consigo 16 ....
max_digits10
para denotar o mesmo. Corrigida a resposta para refletir isso.
Use std::setprecision
:
std::cout << std::setprecision (15) << 3.14159265358979 << std::endl;
std::setprecision (17)
duplo, veja os comentários na resposta de @Bill The Lizard.
Aqui está o que eu usaria:
std::cout << std::setprecision (std::numeric_limits<double>::digits10 + 1)
<< 3.14159265358979
<< std::endl;
Basicamente, o pacote de limites possui características para toda a construção em tipos.
Uma das características dos números de ponto flutuante (float / double / long double) é o atributo digits10. Isso define a precisão (esqueço a terminologia exata) de um número de ponto flutuante na base 10.
Consulte: http://www.cplusplus.com/reference/std/limits/numeric_limits.html
Para obter detalhes sobre outros atributos.
std::setprecision()
: #include <iomanip>
std::numeric_limits<double>
vez denumberic_limits<double>
1
a std::numeric_limits<double>::digits10
?
max_digits10
um pouco arbitrário digits10+2
. Caso contrário, no caso de float
, long double
, boost::multiprecision::float128
isso irá falhar, uma vez que você precisa +3
, em vez de +2
.
A maneira iostreams é meio desajeitada. Eu prefiro usar boost::lexical_cast
porque calcula a precisão certa para mim. E é rápido também.
#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;
Resultado:
Pi: 3.14159265358979
Por precisão total, suponho precisão média suficiente para mostrar a melhor aproximação ao valor pretendido, mas deve-se ressaltar que double
é armazenado usando a representação da base 2 e a base 2 não pode representar algo tão trivial quanto 1.1
exatamente. A única maneira de obter a precisão total do dobro real (com SEM ROUND OFF ERROR) é imprimir os bits binários (ou nybbles hexadecimais). Uma maneira de fazer isso é escrever double
para union
e depois imprimir o valor inteiro dos bits.
union {
double d;
uint64_t u64;
} x;
x.d = 1.1;
std::cout << std::hex << x.u64;
Isso lhe dará a precisão 100% exata do duplo ... e será totalmente ilegível porque os humanos não podem ler o formato duplo IEEE! A Wikipedia tem uma boa descrição de como interpretar os bits binários.
No C ++ mais recente, você pode fazer
std::cout << std::hexfloat << 1.1;
Aqui está como exibir um duplo com precisão total:
double d = 100.0000000000005;
int precision = std::numeric_limits<double>::max_digits10;
std::cout << std::setprecision(precision) << d << std::endl;
Isso exibe:
100.0000000000005
max_digits10 é o número de dígitos necessários para representar exclusivamente todos os valores duplos distintos. max_digits10 representa o número de dígitos antes e depois do ponto decimal.
Não use set_precision (max_digits10) com std :: fixed.
Na notação fixa, set_precision () define o número de dígitos somente após o ponto decimal. Isso está incorreto, pois max_digits10 representa o número de dígitos antes e depois do ponto decimal.
double d = 100.0000000000005;
int precision = std::numeric_limits<double>::max_digits10;
std::cout << std::fixed << std::setprecision(precision) << d << std::endl;
Isso exibe resultado incorreto:
100.00000000000049738
Nota: Arquivos de cabeçalho necessários
#include <iomanip>
#include <limits>
100.0000000000005
não está sendo representado exatamente como a double
. (Pode parecer que deveria, mas não, porque é normalizado , ou seja, sua representação binária). Para ver isso, tente: 100.0000000000005 - 100
. Nós recebemos 4.973799150320701e-13
.
Como imprimo um
double
valor com precisão total usando cout?
Use hexfloat
ou
use scientific
e defina a precisão
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
Muitas respostas tratam apenas de 1) base 2) layout fixo / científico ou 3) precisão. Muitas respostas com precisão não fornecem o valor adequado necessário. Daí esta resposta a uma pergunta antiga.
A double
certamente é codificado usando a base 2. Uma abordagem direta com o C ++ 11 é imprimir usando std::hexfloat
.
Se uma saída não decimal é aceitável, estamos prontos.
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
ou scientific
?A double
é um tipo de ponto flutuante , não ponto fixo .
Você não utilizar std::fixed
como que não consegue imprimir pequena double
como qualquer coisa mas 0.000...000
. Em geral double
, imprime muitos dígitos, talvez centenas de informações questionáveis.
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
Para imprimir com precisão total, use primeiro o std::scientific
que "escreverá valores de ponto flutuante em notação científica". Observe que o padrão de 6 dígitos após o ponto decimal, uma quantidade insuficiente, é tratado no próximo ponto.
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
Um double
codificado usando a base binária 2 codifica a mesma precisão entre várias potências de 2. Isso geralmente é 53 bits.
[1,0 ... 2,0) existem 2 53 diferentes double
,
[2,0 ... 4,0) existem 2 53 diferentes double
,
[4,0 ... 8,0) existem 2 53 diferentes double
,
[8,0 ... 10,0) existem 2 / 8 * 2 53 diferentes double
.
No entanto, se impressões de código decimal com N
algarismos significativos, o número de combinações [1.0 ... 10.0) é 10/9 * 10 N .
Qualquer que seja N
(precisão) escolhida, não haverá um mapeamento individual entre double
e texto decimal. Se um fixo N
for escolhido, algumas vezes será um pouco mais ou menos do que o necessário para determinados double
valores. Podemos errar em muito poucos ( a)
abaixo) ou muitos ( b)
abaixo).
3 candidato N
:
a) Use um N
modo quando, ao converter de texto em double
texto, chegamos ao mesmo texto para todos double
.
std::cout << dbl::digits10 << '\n';
// Typical output
15
b) Use um N
so ao converter de double
-text- double
chegamos ao mesmo double
para todos double
.
// C++11
std::cout << dbl::max_digits10 << '\n';
// Typical output
17
Quando max_digits10
não estiver disponível, observe que, devido aos atributos da base 2 e da base 10 digits10 + 2 <= max_digits10 <= digits10 + 3
, podemos usar digits10 + 3
para garantir que dígitos decimais suficientes sejam impressos.
c) Use um N
que varia com o valor.
Isso pode ser útil quando o código deseja exibir o mínimo de texto ( N == 1
) ou o valor exato de a double
( N == 1000-ish
no caso de denorm_min
). No entanto, como esse é "trabalho" e provavelmente não é o objetivo do OP, será deixado de lado.
Geralmente é b) usado para "imprimir um double
valor com precisão total". Alguns aplicativos podem preferir: a) erro ao não fornecer muitas informações.
Com .scientific
, .precision()
define o número de dígitos a serem impressos após o ponto decimal, para que os 1 + .precision()
dígitos sejam impressos. O código precisa de max_digits10
dígitos totais, então .precision()
é chamado com a 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()
definir o número de casas decimais para o modo científico. Sem especificar scientific
, ele define o número total de dígitos, excluindo o expoente. Você ainda pode ter resultados científicos, dependendo do valor numérico, mas também poderá obter menos dígitos do que o especificado. Exemplo: os cout.precision(3); cout << 1.7976931348623158e+308; // "1.8e+308"
resultados para printf
podem ser diferentes. Coisas confusas que devemos ter em mente.
char buf[DBL_DECIMAL_DIG + 3 + 5]; sprintf(buf, "%.*g", DBL_DECIMAL_DIG, d);
Os caracteres extras são para: sinal, ponto decimal, zero à direita, e [+ | -], 3 dígitos para o expoente ( DBL_MAX_10_EXP = 308). Portanto, o número total de caracteres necessários é 25.
printf("%.12f", M_PI);
% .12f significa ponto flutuante, com precisão de 12 dígitos.
Mais portàvel ...
#include <limits>
using std::numeric_limits;
...
cout.precision(numeric_limits<double>::digits10 + 1);
cout << d;
Com ostream :: precision (int)
cout.precision( numeric_limits<double>::digits10 + 1);
cout << M_PI << ", " << M_E << endl;
vai render
3.141592653589793, 2.718281828459045
Por que você tem que dizer "+1" Eu não tenho idéia, mas o dígito extra que você obtém está correto.
Isso mostrará o valor até duas casas decimais após o ponto.
#include <iostream>
#include <iomanip>
double d = 2.0;
int n = 2;
cout << fixed << setprecison(n) << d;
Veja aqui: Notação de ponto fixo
Usar notação de ponto flutuante fixo Define o sinalizador de formato de campo flutuante para o fluxo str ser fixo.
Quando floatfield é definido como fixo, os valores de ponto flutuante são gravados usando a notação de ponto fixo: o valor é representado com exatamente o número de dígitos na parte decimal, conforme especificado pelo campo de precisão (precisão) e sem a parte do expoente.
Definir precisão decimal Define a precisão decimal a ser usada para formatar valores de ponto flutuante nas operações de saída.
Se você estiver familiarizado com o padrão IEEE para representar os pontos flutuantes, saberia que é impossível mostrar pontos flutuantes com precisão total fora do escopo do padrão , ou seja, isso sempre resultará em um arredondamento do valor real.
Você precisa primeiro verificar se o valor está dentro do escopo ; se sim, use:
cout << defaultfloat << d ;
Usar notação de ponto flutuante padrão Define o sinalizador de formato floatfield para o fluxo str como defaultfloat.
Quando floatfield é definido como defaultfloat, os valores de ponto flutuante são gravados usando a notação padrão: a representação usa quantos dígitos significativos forem necessários até a precisão decimal (precisão) do fluxo, contando os dígitos antes e depois do ponto decimal (se houver) )
Esse também é o comportamento padrão de cout
, o que significa que você não o usa explicitamente.
fixed
? Comdouble h = 6.62606957e-34;
,fixed
me dá0.000000000000000
escientific
saídas6.626069570000000e-34
.