int ((0.1 + 0.7) * 10) = 7 en varios idiomas. ¿Cómo prevenir esto?

Recientemente me encontré con un error / función en varios idiomas. Tengo un conocimiento muy básico acerca de cómo se causa (y me gustaría una explicación detallada), pero cuando pienso en todos los errores que debo haber cometido a lo largo de los años, la pregunta es cómo puedo determinar ” Oye, esto podría causar un error ridículo, es mejor que use funciones de precisión arbitrarias “, qué otros idiomas tienen este error (y aquellos que no, por qué ). Además, ¿por qué 0.1 + 0.7 hace esto y es decir, 0.1 + 0.3 no, hay otros ejemplos bien conocidos?

PHP

//the first one actually doesn't make any sense to me, //why 7 after typecast if it's represented internally as 8? debug_zval_dump((0.1+0.7)*10); //double(8) refcount(1) debug_zval_dump((int)((0.1+0.7)*10)); //long(7) refcount(1) debug_zval_dump((float)((0.1+0.7)*10)); //double(8) refcount(1) 

Pitón:

 >>> ((0.1+0.7)*10) 7.9999999999999991 >>> int((0.1+0.7)*10) 7 

Javascript:

 alert((0.1+0.7)*10); //7.999999999999999 alert(parseInt((0.7+0.1)*10)); //7 

Rubí:

 >> ((0.1+0.7)*10).to_i => 7 >>((0.1+0.7)*10) => 7.999999999999999 

Lo que todo científico informático debe saber sobre la aritmética de punto flotante

No es un problema de idioma. Es un problema general con la aritmética de punto flotante .

Deja de usar flotadores . No realmente.

La representación de números en coma flotante no es exacta .

En Python, int trunca las flotaciones hacia cero al entero más cercano. (int) en PHP, parseInt en Javascript, y to_i en Ruby hacen lo mismo.

Esto no es un error; Es solo cómo funcionan estas funciones.

Por ejemplo, de los documentos para int de Python:

La conversión de números de coma flotante a números enteros se trunca (hacia cero).

Este es un problema conocido que tiene que ver con la representación de punto flotante, desde donde puede encontrar más información aquí:

http://en.wikipedia.org/wiki/IEEE_754-2008

El problema específico es que 7.9 se convertirá directamente (truncado) a 7 mientras se transforma en un int. En Python puedes resolver esto con:

 int( round(((0.1+0.7)*10)) ) 

… y similarmente en otros idiomas.

Pero sí, esto puede ser un problema en muchas situaciones. Los números de punto flotante no son lo suficientemente confiables para los progtwigs de nómina, por ejemplo.

Quizás otros puedan darte otros consejos. Hpe esto ayuda, de todos modos.

Usa el módulo decimal :

 >>> int((decimal.Decimal('0.1')+decimal.Decimal('0.7'))*10) 8 

PHP usa números de punto flotante por defecto, necesita convertirlos manualmente a números enteros.

Debe tener en cuenta la aritmética de punto flotante. Las otras publicaciones aquí proporcionan suficientes enlaces sobre eso.

Personalmente uso round / ceil / float dependiendo de lo que espero en lugar de int

 $a = (int) round((0.7 + 0.1) * 10);