2012-04-24 30 views
11

Tengo un programa que busca rutas en un gráfico y genera el peso acumulado. Todos los bordes en el gráfico tienen un peso individual de 0 a 100 en forma de un flotador con un máximo de 2 decimales.0 + 0 + 0 ... + 0! = 0

En Windows/Visual Studio 2010, para una ruta particular que consta de bordes con 0 ponderaciones, genera el peso total correcto de 0. Sin embargo, en Linux/GCC el programa dice que la ruta tiene un peso de 2.35503e-38. He tenido muchas experiencias con bichos raros causados ​​por carrozas, pero ¿cuándo 0 + 0 igualaría alguna cosa que no fuera 0?

Lo único que puedo pensar que está causando esto es que el programa trata algunos de los pesos como enteros y usa la coerción implícita para agregarlos al total. ¡Pero 0 + 0.0f todavía es igual a 0.0f! Como solución rápida, reduzco el total a 0 cuando es menor que 0.00001 y eso es suficiente para mis necesidades, por ahora. Pero, ¿qué vodoo causa esto?

NOTA: estoy 100% seguro de que ninguno de los pesos en el gráfico exceder el rango he mencionado y que todos los pesos en este camino en particular son todos 0.

EDIT: Elaborar , He intentado tanto leer los pesos de un archivo como configurarlos en el código de forma manual como igual a 0.0f No se está realizando ninguna otra operación en ellos aparte de agregarlos al total.

+19

¿Puede construir un caso de prueba mínimo? –

+0

@OliCharlesworth Eso es lo que he estado tratando de hacer, hasta ahora sin suerte. La cantidad de código relevante es demasiado para publicar, pero continuaré intentando reproducir el error en un ámbito más pequeño. Esperaba que hubiera un razonamiento obvio detrás de esto. –

+0

Le recomendaría que estudie la definición de máquina épsilon. Esto parece ser lo que está causando tu error aquí. – andre

Respuesta

11

Porque es un número de punto flotante IEEE, y no es exactamente igual a cero.

http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm

+3

Pero la pregunta es: ¿por qué? (como en, ¿por qué no es cero?) Sin embargo, no es posible responder (todavía), porque necesitamos ver un caso de prueba del PO. –

+0

He estudiado puntos flotantes bastante en mi curso de Análisis Numérico de pregrado, pero nunca he encontrado un caso en el que 0 + 0 sea alguna vez diferente a 0. Nunca haré ninguna otra operación en él. –

+0

http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm ¿Por qué 0 no es 0?Creo que la sección "Zeros" dice que 0 es 0 y está representado con precisión en las reglas IEEE 754. –

3

Puede ser que sus flotadores que contienen valores de "0.0f" no son realmente 0.0f (0x00000000 representación de bits), pero un muy, muy pequeño número que evalúa a aproximadamente 0,0. Debido a la forma en que la especificación IEEE754 define representaciones flotantes, si tiene, por ejemplo, una mantisa muy pequeña y un exponente 0, mientras que no es igual a 0 absoluto, redondeará a 0. Sin embargo, si suma estos números, número de veces, la cantidad muy pequeña se acumulará en un valor que eventualmente se volverá distinto de cero.

Aquí es un caso de ejemplo que da la ilusión de 0 es distinto de cero:

float f = 0.1f/1000000000; 
printf("%f, %08x\n", f, *(unsigned int *)&f); 
float f2 = f * 10000; 
printf("%f, %08x\n", f2, *(unsigned int *)&f2); 

Si va a asignar literales a sus variables y la adición de ellos, sin embargo, es posible que sea el compilador no es traduciendo 0 en 0x0 en la memoria. Si es así, y esto todavía está sucediendo, entonces también es posible que su hardware de CPU tenga un error relacionado con convertir los 0 en no-cero al hacer operaciones ALU que pueden haber chirrido por sus esfuerzos de validación.

Sin embargo, es bueno recordar que el punto flotante IEEE es solo una aproximación, y no una representación exacta de ningún valor de flotación particular. Por lo tanto, cualquier operación de coma flotante tendrá alguna cantidad de error.

+0

No, esto no se parece en nada a mi caso. NO estoy dividiendo, nunca. Solo estoy asignando 0 y 0.0f a las variables y luego las agrego. –

+0

Doy un ejemplo de lo que puede causar la ilusión. Por supuesto, muchas situaciones diferentes podrían causar algo similar. –

+0

Correcto, nunca pensé que agregar 0 constantes podría causar esto. –

5

en [...] forma de un flotador con un máximo de 2 decimales.

No hay tal cosa como un flotador con en la mayoría de 2 cifras decimales. Los flotantes casi siempre se representan como un número de punto flotante binario (mantisa binaria fraccional y exponente entero). Tantos (la mayoría) de los números con dos decimales no se pueden representar exactamente.

Por ejemplo, 0.20f puede parecer como una fracción inocente y redonda, pero

printf("%.40f\n", 0.20f); 

imprimirá: 0,2000000029802322387695312500000000000000.

Ver, no tiene 2 decimales, tiene 26 !!!

Naturalmente, para la mayoría de los usos prácticos la diferencia es insignificante. Pero si hace algunos cálculos, puede terminar aumentando el error de redondeo y hacerlo visible, particularmente alrededor de 0.

+0

Estaba al tanto de esto para valores distintos de cero, pero mi problema surge cuando se trata solo de 0. Sin embargo, para un gran número de ceros que están ligeramente apagados, tal vez eso está causando el problema como se señala en otra respuesta. –

+0

¿Y cómo sabes que estás tratando exactamente con los 0? ¿Son constantes del compilador? Leer de un archivo? – rodrigo

+0

Intenté usar constantes y leer desde un archivo. –

Cuestiones relacionadas