La precisión de la larga doble salida no es correcta. ¿Qué podría estar mal?
-
22-08-2019 - |
Pregunta
Tengo una constante que me he fijado ya sea como const o no-const long double
. Es más largo (40 dígitos) que la precisión de un long double
en mi prueba de estación de trabajo (19 dígitos).
Al imprimir a cabo, ya no aparece a los 19 dígitos de precisión, pero a los 16 años.
Este es el código que estoy probando:
#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
Salida:
$ ./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
Yo esperaría 0.6931471805599453094
pero en lugar de obtener 0.6931471805599452862
.
¿Hay una razón por la que los 19 dígitos de precisión se cortan a 16 dígitos?
Aquí está mi entorno:
$ gcc --version
i686-apple-darwin9-g++-4.0.1 (GCC) 4.0.1 (Apple Inc. build 5490)
Estoy viendo el mismo problema con otras versiones de gcc, por ejemplo:.
$ gcc --version
g++ (GCC) 3.4.6 20060404 (Red Hat 3.4.6-10)
Puedo mirar en NTL u otras bibliotecas, pero tengo curiosidad por lo que está causando esto. Gracias por su comprensión.
Solución
Me sale este resultado:
19
const via cout: 0.6931471805599453094
non-const via cout: 0.6931471805599453094
const via printf: 0.6931471805599453094
non-const via printf: 0.6931471805599453094
Pero estoy usando literales dobles largos en lugar de literales dobles:
const long double constLog2 = 0.6931471805599453094172321214581765680755L;
long double log2 = 0.6931471805599453094172321214581765680755L;
Otros consejos
Hay algunos problemas sutiles relacionados con las plataformas de hardware y compilar las opciones que podrían ser de interés:
- https://www.amazon.com/exec/obidos/ASIN/0954161793 / análisis de redes-20
- 3.17.3 Intel 386 y AMD x86-64 opciones (gcc-4.0.1) (documentación archivada developer.apple.com)
- 03/17/12 Intel 386 y AMD x86-64 opciones (gcc-4.0.1) (documentación gcc.gnu.org)
Estas opciones `-m' se definen para el i386 y x86-64 familia de ordenadores:
-m96bit-largo doble
-m128bit-largo doble
Estos conmutadores controlan el tamaño de tipo largo doble. La interfaz de aplicación binaria i386 especifica el tamaño sea de 96 bits, por lo -m96bit-largo es el doble defecto en el modo de 32 bits. arquitecturas modernas (Pentium y posteriores) preferirían larga doble a estar alineadas a un 8 o 16 límite de byte. En matrices o estructuras conforme a la ABI, esto no haría ser posible. Así que especifica una -m128bit-largo doble alineará largo doble a un límite de 16 bytes por el relleno de la larga doble con una adicional cero 32 bits.
En el compilador x86-64, -m128bit-largo doble es la opción por defecto como su ABI especifica que a largo doble es para ser alineado en 16 byte Perímetro.
Tenga en cuenta que ninguna de estas opciones permitir a cualquier precisión adicional sobre el estándar x87 de 80 bits por un largo doble.
Advertencia: Si anula el valor predeterminado valor por su objetivo ABI, la estructuras y matrices que contienen largo las variables dobles cambiarán su tamaño, así como la función que llama Convención para la función de dar largos doble se modificará. De ahí que no será compatible a nivel binario con matrices o estructuras en código compilado sin que el interruptor.