La precisione della lunga doppia uscita non è corretta. Che cosa potrebbe essere sbagliato?
-
22-08-2019 - |
Domanda
Ho un long double
costante che sto installando sia come const o no-const. E 'più lungo (40 cifre) che la precisione di un long double
sulla mia workstation di prova (19 cifre).
Quando stampo fuori, non è più visualizzata a 19 cifre di precisione, ma a 16 anni.
Ecco il codice che sto 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;
}
Compila:
$ 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
mi aspetterei 0.6931471805599453094
ma invece ottenere 0.6931471805599452862
.
C'è un motivo che i 19 cifre di precisione sono tagliati a 16 cifre?
Qui è il mio ambiente:
$ gcc --version
i686-apple-darwin9-g++-4.0.1 (GCC) 4.0.1 (Apple Inc. build 5490)
sto vedendo lo stesso problema con altre versioni di gcc, per esempio:.
$ gcc --version
g++ (GCC) 3.4.6 20060404 (Red Hat 3.4.6-10)
posso guardare in NTL o altre librerie, ma sono curioso di ciò che sta causando questo. Grazie per la vostra comprensione.
Soluzione
ottengo questo output:
19
const via cout: 0.6931471805599453094
non-const via cout: 0.6931471805599453094
const via printf: 0.6931471805599453094
non-const via printf: 0.6931471805599453094
Ma sto usando lunghi letterali matrimoniali invece di doppi letterali:
const long double constLog2 = 0.6931471805599453094172321214581765680755L;
long double log2 = 0.6931471805599453094172321214581765680755L;
Altri suggerimenti
Ci sono alcune questioni relative alla sottili piattaforme hardware e compilare le opzioni che potrebbero essere di interesse:
- https://www.amazon.com/exec/obidos/ASIN/0954161793 / networktheory-20
- 3.17.3 Intel 386 e AMD x86-64 Opzioni (gcc-4.0.1) (archiviata la documentazione developer.apple.com)
- 3.17.12 Intel 386 e AMD x86-64 Opzioni (gcc-4.0.1) (documentazione gcc.gnu.org)
Queste opzioni `-m' sono definiti per l'i386 e x86-64 famiglia di computer:
-m96bit-lungo doppio
-m128bit-lungo doppio
Questi interruttori controllano la dimensione di tipo lungo doppio. L'interfaccia binaria applicazione i386 Specifica la dimensione sia 96 bit, così --M96bit-lungo doppio è l'impostazione predefinita in modalità a 32 bit. architetture moderne (Pentium e successivi) preferirebbero lunga doppio per essere allineato con un 8 o 16 limite di byte. In array o strutture conforme al ABI, questo non sarebbe Essere possibile. Quindi, specificando un --M128bit-lungo doppio allineerà long double a un limite di 16 byte per imbottitura la lunga doppia con un ulteriori 32 bit a zero.
Nel compilatore x86-64, --M128bit-long double è la scelta di default come il suo ABI specifica che a lungo doppio deve essere allineata a 16 byte confine.
Si noti che nessuna di queste opzioni permettere a qualsiasi precisione in più oltre il norma x87 80 bit per un lungo Doppio.
Attenzione: se si ignora il valore di default valore per il vostro obiettivo di ABI, il strutture e matrici contenenti lungo variabili doppie cambieranno il loro dimensioni così come la funzione di chiamata convenzione per la funzione presa lungo doppia verrà modificato. Perciò essi non sarà compatibile con binario array o strutture in codice compilato senza che l'interruttore.