A precisão da saída dupla longa não é correto. O que pode estar errado?
-
22-08-2019 - |
Pergunta
Eu tenho uma constante long double
que estou definindo quer como const ou não-const. É mais longos (40 dígitos) do que a precisão de um long double
no meu trabalho de teste (19 dígitos).
Quando eu imprimi-lo, já não é exibido em 19 dígitos de precisão, mas aos 16 anos.
Aqui está o código que estou testando:
#include <iostream>
#include <iomanip>
#include <limits>
#include <cstdio>
int main ()
{
const long double constLog2 = 0.6931471805599453094172321214581765680755;
long double log2 = 0.6931471805599453094172321214581765680755;
std::cout << std::numeric_limits<long double>::digits10 + 1 << std::endl;
std::cout << "const via cout: " << std::setprecision(19) << constLog2 << std::endl;
std::cout << "non-const via cout: " << std::setprecision(19) << log2 << std::endl;
std::fprintf(stdout, "const via printf: %.19Lf\n", constLog2);
std::fprintf(stdout, "non-const via printf: %.19Lf\n", log2);
return 0;
}
Compilar:
$ g++ -Wall precisionTest.cpp
Output:
$ ./a.out
19
const via cout: 0.6931471805599452862
non-const via cout: 0.6931471805599452862
const via printf: 0.6931471805599452862
non-const via printf: 0.6931471805599452862
Eu esperaria 0.6931471805599453094
mas sim obter 0.6931471805599452862
.
Existe uma razão que os 19 dígitos de precisão são cortadas para 16 dígitos?
Aqui está o meu ambiente:
$ gcc --version
i686-apple-darwin9-g++-4.0.1 (GCC) 4.0.1 (Apple Inc. build 5490)
Eu estou vendo o mesmo problema com outras versões do gcc, p.ex.:.
$ gcc --version
g++ (GCC) 3.4.6 20060404 (Red Hat 3.4.6-10)
Eu posso olhar para NTL ou outras bibliotecas, mas estou curioso o que está causando isso. Obrigado pela sua compreensão.
Solução
Eu recebo esta saída:
19
const via cout: 0.6931471805599453094
non-const via cout: 0.6931471805599453094
const via printf: 0.6931471805599453094
non-const via printf: 0.6931471805599453094
Mas eu estou usando literais longa casal em vez de literais duplas:
const long double constLog2 = 0.6931471805599453094172321214581765680755L;
long double log2 = 0.6931471805599453094172321214581765680755L;
Outras dicas
Existem alguns problemas sutis relacionados com plataformas de hardware e opções de compilação que possam ser de interesse:
- https://www.amazon.com/exec/obidos/ASIN/0954161793 / análise de rede-20
- 3.17.3 Intel 386 e AMD x86-64 Opções (gcc-4.0.1) (arquivado developer.apple.com documentação)
- 3.17.12 Intel 386 e AMD x86-64 Opções (gcc-4.0.1) (gcc.gnu.org documentação)
Estas `opções -m' são definidos para o i386 e x86-64 família de computadores:
-m96bit-long-double
-m128bit-long-double
Estes interruptores controlar o tamanho do tipo double long. A interface binária i386 aplicação especifica o tamanho para ser de 96 bits, então -m96bit-long-dupla é o padrão no modo de 32 bits. arquiteturas modernas (Pentium e mais recentes) prefere longo duplo para ser alinhado a um 8 ou 16 byte fronteira. Em matrizes ou de estruturas em conformidade com a ABI, isso não faria seja possível. Então, especificando um -m128bit-longo-dupla irá alinhar longo duplo para um limite de 16 bytes pela preenchimento do long double com um de 32 bit zero.
No compilador x86-64, -m128bit-long-dupla é a opção padrão como seus especifica ABI tanto tempo duplo é para ser alinhado no byte 16 fronteira.
Observe que nenhuma dessas opções permitir que qualquer precisão extra sobre o x87 padrão de 80 bits para um longo Duplo.
Aviso: se você substituir o padrão valor para o seu alvo ABI, o estruturas e matrizes contendo longo variáveis ??duplas vai mudar a sua função de chamada, bem como o tamanho convenção para a tomada de função longo dupla será modificado. Daí eles não vai ser binário compatível com matrizes ou de estruturas em código compilado sem que o interruptor.