c++ - precisión - punto flotante simple precision
Advertencia por constantes de coma flotante inexactas (4)
Preguntas como " ¿Por qué no es 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 = 0.8? " Me hicieron pensar que ...
... Probablemente sería bueno que el compilador advierta acerca de las constantes de punto flotante que redondea al representable más cercano en el tipo binario de punto flotante (por ejemplo, 0.1 y 0.8 están redondeadas en punto flotante radix-2, de lo contrario, necesitaría una cantidad infinita de espacio para almacenar la cantidad infinita de dígitos).
He buscado avisos de gcc y hasta ahora no he encontrado ninguno para este fin ( -Wall
, -Wextra
, -Wfloat-equal
, -Wconversion
, -Wcoercion
(no compatible o solo C?), -Wtraditional
(C solamente) no aparecen estar haciendo lo que quiero).
Tampoco encontré tal advertencia en el compilador de Microsoft Visual C ++.
¿Me falta una opción oculta o rara vez utilizada?
¿Hay algún compilador que tenga este tipo de advertencia?
EDITAR : Esta advertencia podría ser útil con fines educativos y servir como un recordatorio para los nuevos en punto flotante.
La advertencia está en la fuente: cuando escribe float
, double
o long double
incluyendo cualquiera de sus respectivos literales. Obviamente, algunos literales son exactos, pero incluso esto no ayuda mucho: la suma de dos valores exactos puede ser inexacta, por ejemplo, si tienen escalas bastante diferentes. Hacer que el compilador advierta sobre constantes inexactas de coma flotante generaría una falsa sensación de seguridad. Además, ¿qué se supone que debes hacer con las constantes redondeadas? Escribir el valor exacto más cercano explícitamente sería propenso a errores y ofuscaría el intento. Escribirlos de manera diferente, por ejemplo, escribir 1.0 / 10.0
lugar de 0.1
también ofusca la intención y podría arrojar valores diferentes.
No habrá tal cambio de compilador y la razón es obvia. Estamos anotando los componentes binarios en decimal:
El primer bit fraccionario es 0.5
El segundo bit fraccional es 0.25
El tercer bit fraccional es 0.125
....
Lo ves ? Debido a las terminaciones impares con el número 5, cada bit necesita otro decimal para representarlo exactamente. Un bit necesita un decimal, dos bits necesita dos decimales, y así sucesivamente.
Por lo tanto, para los puntos flotantes fraccionarios, significa que para la mayoría de los números decimales necesita 24 (!) Dígitos decimales para los flotadores de precisión simple y 53 (!!) dígitos decimales para la precisión doble. Peor aún, los dígitos exactos no llevan información adicional, son artefactos puros causados por el cambio de base.
Nadie va a escribir 3.141592653589793115997963468544185161590576171875 para pi para evitar una advertencia del compilador.
No hay ninguna razón técnica por la que el compilador no pueda emitir tales advertencias. Sin embargo, serían útiles solo para los estudiantes (a quienes debería enseñarse cómo funciona la aritmética de punto flotante antes de que comiencen a hacer un trabajo serio con ella) y las personas que trabajan muy bien con punto flotante. Desafortunadamente, la mayoría del trabajo de punto flotante es áspero; las personas arrojan números a la computadora sin importar mucho cómo funciona la computadora, y aceptan los resultados que obtienen.
La advertencia debería estar desactivada de forma predeterminada para admitir la mayor parte del código de punto flotante existente. Si estuviese disponible, lo activaría para mi código en la biblioteca matemática Mac OS X. Ciertamente, hay puntos en la biblioteca donde dependemos de cada bit del valor de coma flotante, como los lugares donde usamos la aritmética de precisión extendida, y los valores están representados en más de un objeto de coma flotante (por ejemplo, tendríamos uno objeto con los bits altos de 1 / π, otro objeto con 1 / π menos el primer objeto, y un tercer objeto con 1 / π menos los primeros dos objetos, que nos da alrededor de 150 bits de 1 / π). Algunos de estos valores se representan en coma flotante hexadecimal en el texto de origen, para evitar cualquier problema con la conversión del compilador de numerales decimales, y podríamos convertir fácilmente los números restantes para evitar la nueva advertencia del compilador.
Sin embargo, dudo que podamos convencer a los desarrolladores del compilador de que suficientes personas usarían esta advertencia o que atraparía suficientes errores para que valga la pena su tiempo. Considera el caso de la libma. Supongamos que generalmente escribimos números exactos para todas las constantes pero, en una ocasión, escribimos algún otro número. ¿Esta advertencia atraparía un error? Bueno, ¿qué error hay? Lo más probable es que el número se convierta exactamente en el valor que queríamos de todos modos. Cuando se escribe código con esta advertencia encendida, es probable que pensemos en cómo se realizarán los cálculos de coma flotante, y el valor que hemos escrito es el adecuado para nuestro propósito. Por ejemplo, puede ser un coeficiente de algún polinomio minimax que calculamos, y el coeficiente es tan bueno como lo que va a obtener, ya sea representado aproximadamente en decimales o convertido en algún número hexadecimal flotante exactamente representable.
Por lo tanto, esta advertencia raramente detectará errores. Tal vez atrape una ocasión en la que hayamos escrito mal un número, insertando accidentalmente un dígito extra en un número hexadecimal de punto flotante, haciendo que se extienda más allá del significado representativo. Pero eso es raro En la mayoría de los casos, los números que utilizamos son simples y cortos o se copian y pegan del software que los ha calculado. En algunas ocasiones, proporcionaremos valores especiales de tipo manual, como 0x1.fffffffffffffp0. Una advertencia cuando una "f" adicional se desliza en ese número podría detectar un error durante la compilación, pero ese error casi con seguridad se detectaría rápidamente en las pruebas, ya que altera drásticamente el valor especial.
Entonces, tal advertencia de compilador tiene poca utilidad: muy pocas personas la usarán y detectará muy pocos errores para las personas que sí la usan.
No veo cómo lo sabría un compilador o que el compilador puede advertirte sobre algo así. Es solo una coincidencia que un número puede ser representado exactamente por algo que es inherentemente inexacto.