float bytes c double 32bit-64bit

bytes - La multiplicación doble difiere entre el tiempo de compilación y el tiempo de ejecución en una plataforma de 32 bits



float size c (3)

En general, nunca haga verificaciones de igualdad con números de punto flotante . Debe comprobar si el resultado que desea difiere del resultado que obtiene en menos de una precisión preestablecida.

Lo que está sucediendo aquí es probablemente debido a la multiplicación que se ejecuta en dos "plataformas" diferentes: una vez por su código, y una vez por el compilador, que puede tener una precisión diferente. Esto sucede con la most compilers .

Su programa probablemente funcionaría si lo compilara con las mismas opciones que se usaron para compilar el compilador (suponiendo que el compilador se compiló solo). Pero eso no significaría que obtendrías el resultado correcto ; obtendrías el mismo error de precisión que el compilador.

(Además, asumo que el compilador realiza una multiplicación directa y que el código de análisis que reconoce los flotadores no entra en la ecuación. Esto podría ser una ilusión de mi parte).

Pruebas

Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/lib64/gcc/x86_64-suse-linux/4.8/lto-wrapper Target: x86_64-suse-linux Configured with: ../configure --prefix=/usr --infodir=/usr/share/info --mandir=/usr/share/man --libdir=/usr/lib64 --libexecdir=/usr/lib64 --enable-languages=c,c++,objc,fortran,obj-c++,java,ada --enable-checking=release --with-gxx-include-dir=/usr/include/c++/4.8 --enable-ssp --disable-libssp --disable-plugin --with-bugurl=http://bugs.opensuse.org/ --with-pkgversion=''SUSE Linux'' --disable-libgcj --disable-libmudflap --with-slibdir=/lib64 --with-system-zlib --enable-__cxa_atexit --enable-libstdcxx-allocator=new --disable-libstdcxx-pch --enable-version-specific-runtime-libs --enable-linker-build-id --enable-linux-futex --program-suffix=-4.8 --without-system-libunwind --with-arch-32=i586 --with-tune=generic --build=x86_64-suse-linux --host=x86_64-suse-linux Thread model: posix gcc version 4.8.3 20141208 [gcc-4_8-branch revision 218481] (SUSE Linux) #include <stdio.h> int main() { double y = 8.34214e08; double z = 1.25823e45; return printf("%s/n", y * z == 8.34214e08 * 1.25823e45 ? "Equal" : "NOT equal!"); }

Obligando a -O0 para evitar que el compilador optimice el código completo (gracias @markgz!), Obtenemos

$ gcc -m32 -O0 -o float.c && ./float ¡NO es igual! $ gcc -m32 -frounding-math -O0 -o float float.c && ./float Equal

Para que conste, desde que llegaste antes que yo :-),

Matemáticas

Deshabilite las transformaciones y optimizaciones que asumen el comportamiento de redondeo de punto flotante predeterminado. Esto es redondeado a cero para todas las conversiones de coma flotante a entero, y redondeado al más cercano para todos los demás truncamientos aritméticos. Esta opción debe especificarse para los programas que cambian el modo de redondeo de FP dinámicamente, o que se pueden ejecutar con un modo de redondeo no predeterminado. Esta opción desactiva el plegado constante de expresiones de punto flotante en el momento de la compilación (que puede verse afectada por el modo de redondeo) y las transformaciones aritméticas que no son seguras en presencia de modos de redondeo dependientes de signo.

El valor predeterminado es -fno-rounding-math.

Estoy compilando y ejecutando el siguiente programa en plataformas de 32 y 64 bits:

int main() { double y = 8.34214e08; double z = 1.25823e45; return y * z == 8.34214e08 * 1.25823e45; }

Mientras que en 64 bits el resultado es el esperado (los valores son los mismos y el código de salida es distinto de cero) en 32 bits parece que hay una pequeña diferencia entre el valor calculado en el momento de la compilación, el lado derecho de la comparación y el lado izquierdo. Lado computado en tiempo de ejecución.

¿Es esto un error en el compilador o hay una explicación lógica?

EDIT: esto es diferente de ¿Por qué comparar el doble y el flotante conduce a un resultado inesperado? Porque aquí todos los valores son dobles.


IEEE-754 permite que los cálculos intermedios se realicen con mayor precisión (énfasis mío).

(IEEE-754: 2008) "Un estándar de lenguaje también debe definir, y requerir implementaciones para proporcionar, atributos que permitan y no permitan optimizaciones de cambio de valor, por separado o colectivamente, para un bloque. Estas optimizaciones pueden incluir, pero no se limitan a: [...] Uso de resultados intermedios más amplios en la evaluación de expresiones ".

En su caso, por ejemplo, en un IA-32, los valores dobles podrían almacenarse en los registros FPU x87 con mayor precisión (80 bits en lugar de 64). Entonces, en realidad estás comparando una multiplicación hecha con precisión doble con una multiplicación hecha con precisión extendida doble.

Por ejemplo, en x64 donde el resultado es 1 (la FPU x87 no se usa como SSE en su lugar), agregar la opción gcc -mfpmath=387 para usar el x87 hace que el resultado cambie a 0 en mi máquina.

Y si te preguntas si C también lo permite, es:

(C99, 6.3.1.p8) "Los valores de los operandos flotantes y de los resultados de las expresiones flotantes se pueden representar con mayor precisión y rango que los requeridos por el tipo";


Los cálculos de punto flotante realizados en tiempo de compilación a menudo ocurren con una precisión mayor que los usos double en tiempo de ejecución. Asimismo, C puede realizar cálculos double intermedios en tiempo de ejecución con la precisión long double más long double . O bien explica tu desigualdad. Ver FLT_EVAL_METHOD para más detalles.

volatile double y = 8.34214e08; volatile double z = 1.25823e45; volatile double yz = 8.34214e08 * 1.25823e45; printf("%.20e/n", y); printf("%.20e/n", z); printf("%.20e/n", yz); printf("%.20Le/n", (long double) y*z); printf("%.20Le/n", (long double) 8.34214e08 * 1.25823e45); 8.34214000000000000000e+08 1.25822999999999992531e+45 // 3 different products! 1.04963308121999993395e+54 1.04963308121999993769e+54 1.04963308122000000000e+54

Sus resultados pueden diferir ligeramente.