Entiendo que la --ffast-math
bandera de gcc puede aumentar en gran medida la velocidad de las operaciones de flotación, y se sale de los estándares IEEE, pero parece que no puedo encontrar información sobre lo que realmente sucede cuando está encendido. ¿Alguien puede explicar algunos de los detalles y tal vez dar un ejemplo claro de cómo algo cambiaría si la bandera estuviera encendida o apagada?
Intenté buscar en SO para preguntas similares, pero no pude encontrar nada que explicara el funcionamiento de las matemáticas rápidas.
double
, pero varía según la aplicación). Una cosa a tener en cuenta es que las optimizaciones de matemáticas rápidas no necesariamente agregan "más" redondeo. La única razón por la que no cumple con IEEE es porque la respuesta es diferente (aunque ligeramente) de lo que está escrito.x
es menor que 10, el error en el ejemplo de Mystical disminuirá alrededor de 10 ^ -10. Pero six = 10e20
, es probable que el error sea de muchos millones.-fassociative-math
lo que está incluido en-funsafe-math-optimizations
la cual a su vez está habilitado con-ffast-math
¿Por qué no optimizar el CCGa*a*a*a*a*a
a(a*a*a)*(a*a*a)
?-ffast-math
hace mucho más que simplemente romper el estricto cumplimiento de IEEE.En primer lugar, por supuesto, rompe el estricto cumplimiento de IEEE, lo que permite, por ejemplo, reordenar las instrucciones a algo que sea matemáticamente igual (idealmente) pero no exactamente igual en coma flotante.
En segundo lugar, deshabilita la configuración
errno
después de las funciones matemáticas de una sola instrucción, lo que significa evitar escribir en una variable local de hilo (esto puede hacer una diferencia del 100% para esas funciones en algunas arquitecturas).En tercer lugar, supone que todas las matemáticas son finitas , lo que significa que no se realizan comprobaciones de NaN (o cero) en el lugar donde tendrían efectos perjudiciales. Simplemente se supone que esto no va a suceder.
Cuarto, permite aproximaciones recíprocas para la división y la raíz cuadrada recíproca.
Además, deshabilita el cero con signo (el código supone que el cero con signo no existe, incluso si el objetivo lo admite) y el redondeo matemático, lo que permite, entre otras cosas, el plegado constante en tiempo de compilación.
Por último, se genera un código que asume que no hay interrupciones de hardware pueden ocurrir debido a la señalización / atrapando matemáticas (es decir, si estos no se puede desactivar en la arquitectura de destino y por lo tanto no suceda , no van a ser manejados).
fuente
-ffast-math
Conjuntos -fno-math-errno, -funsafe-math-optimizations, -ffinite-math-only, -fno-rounding-math, -fno-señalización -nans y -fcx-limited-range. Esta opción hace que se defina la macro del preprocesador FAST_MATH . "y algo de glibc, como (math.h
near math_errhandling)" Por defecto, todas las funciones admiten tanto el manejo de errores como el de excepción. En el modo matemático rápido de gcc y si las funciones en línea están definidas, esto podría no ser cierto. "-ffast-math
permite al compilador cortar algunas esquinas y romper algunas promesas (como se explicó), que en general no es peligroso como tal y no es un problema para la mayoría de las personas. Para la mayoría de las personas, es lo mismo, solo que más rápido. Sin embargo, si su código asume y se basa en estas promesas, entonces su código puede comportarse de manera diferente de lo que espera. Por lo general, esto significa que el programa parecerá funcionar bien, en su mayoría, pero algunos resultados pueden ser "inesperados" (por ejemplo, en una simulación de física, dos objetos podrían no chocar correctamente).-O2
generalmente permite "todas" las optimizaciones legales, excepto aquellas que cambian el tamaño por velocidad.-O3
También permite optimizaciones que cambian el tamaño por la velocidad. Todavía mantiene el 100% de corrección.-ffast-math
intenta hacer que las operaciones matemáticas sean más rápidas permitiendo un comportamiento "ligeramente incorrecto" que generalmente no es dañino, pero se consideraría incorrecto por la redacción de la norma. Si su código es realmente muy diferente en velocidad en dos compiladores (no solo 1-2%), verifique que su código cumpla estrictamente con los estándares y ...#pragma omp parallel for
, y dentro del cuerpo del bucle está leyendo y escribiendo en direcciones señaladas por argumentos de función, y realiza una cantidad no trivial de ramificación. Como una suposición sin educación, es posible que esté intercambiando cachés desde su invocación de subprocesos definida por la implementación, y MSVC puede evitar incorrectamente los almacenes intermedios que las reglas de alias obligarían. Imposible decirlo.