Tengo el siguiente código, sin embargo, al compilarlo con GCC 4.4 con varios indicadores de optimización obtengo algunos resultados inesperados cuando se ejecuta.Problema de GCC con comparaciones de tipo doble sin formato
#include <iostream>
int main()
{
const unsigned int cnt = 10;
double lst[cnt] = { 0.0 };
const double v[4] = { 131.313, 737.373, 979.797, 731.137 };
for(unsigned int i = 0; i < cnt; ++i) {
lst[i] = v[i % 4] * i;
}
for(unsigned int i = 0; i < cnt; ++i) {
double d = v[i % 4] * i;
if(lst[i] != d) {
std::cout << "error @ : " << i << std::endl;
return 1;
}
}
return 0;
}
cuando se compila con: "g ++ -pedantic -Wall -Werror -O1 -o test.cpp test" consigo la salida siguiente: "error @: 3"
cuando se compila con: "g ++ -pedantic -Wall -Werror -O2 -o test.cpp test" consigo la salida siguiente: "error @: 3"
cuando se compila con: "test.cpp g ++ -pedantic -Wall -Werror -O3 -o prueba" me sale ningún error
cuando se compila con: "g ++ -pedantic -Wall - werror -o test.cpp prueba" me sale ningún error
no creo que esto sea un problema relacionado con el redondeo, o diferencia épsilon en la comparación. Intenté esto con Intel v10 y MSVC 9.0 y todos parecen funcionar como se esperaba. Creo que esto no debería ser más que una comparación de bits.
Si se sustituye la sentencia if con lo siguiente: if (static_cast<long long int>(lst[i]) != static_cast<long long int>(d))
, y añadir "-Wno-largo tiempo" me sale ningún error en cualquiera de los modos de optimización cuando se ejecuta.
Si añado std::cout << d << std::endl;
antes de que el "retorno 1", me sale ningún error en cualquiera de los modos de optimización cuando se ejecuta.
¿Esto es un error en mi código, o hay algo mal con GCC y la forma en que maneja el tipo doble?
Nota: Acabo de probar esto con las versiones 4.3 y 3.3 de gcc, el error no se exhibe.
Resolución: Mike Dinsdale en cuenta lo siguiente informe de error: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=323 Parece que el equipo GCC no son completamente seguros sobre la naturaleza del problema.
Como se sugiere en el informe de error, una posible solución es usar la opción ffloat-store. He intentado esto y funciona, sin embargo, los resultados desde el punto de vista del rendimiento no son tan buenos, aunque mmm.
La comparación de 'dobles' se realiza mejor usando un pequeño valor delta para tener en cuenta las imprecisiones en coma flotante. Intente imprimir los valores de 'lst [i]' y 'd' justo antes de la comparación y díganos qué tan diferentes son. – dirkgently
Este no es un escenario donde tengo valores generados a partir de diferentes fuentes y quiero ver si son iguales entre sí dentro de una tolerancia, estos son valores idénticos (bit a bit), deben ser verdaderos. El hecho de que el compilador no genere un binario que proporcione un conjunto coherente de resultados en cualquier sentido es lo que más preocupa. –
@Monomer: considere cambiar el ensamblaje cuando cambie el programa para usar una comparación bit a bit de la FPU. Parece básico, pero esto significa que no usará los valores en la FPU, que pueden estar apagados, y en realidad cargarlos y truncarlos. En pocas palabras, su prueba no es concluyente. – GManNickG