O que a matemática do FCC realmente faz?

Eu entendo que a flag --ffast-math do gcc pode aumentar bastante a velocidade das float ops, e vai além dos padrões IEEE, mas não consigo encontrar informações sobre o que realmente está acontecendo quando está em --ffast-math . Alguém pode explicar alguns detalhes e talvez dar um exemplo claro de como algo mudaria se a bandeira estivesse ligada ou desligada?

Eu tentei cavar através do SO para perguntas semelhantes, mas não consegui encontrar nada que explicasse o funcionamento do ffast-math.

Como você mencionou, ele permite otimizações que não preservam a conformidade estrita do IEEE.

Um exemplo é este:

 x = x*x*x*x*x*x*x*x; 

para

 x *= x; x *= x; x *= x; 

Como a aritmética de ponto flutuante não é associativa, o ordenamento e o fatoramento das operações afetará os resultados devido ao arredondamento. Portanto, essa otimização não é feita sob um comportamento estrito de FP.

Na verdade, não verifiquei se o GCC realmente faz essa otimização específica. Mas a ideia é a mesma.

-ffast-math faz muito mais do que apenas quebrar a conformidade estrita do IEEE.

Em primeiro lugar, é claro, ele quebra rigorosamente a conformidade IEEE, permitindo, por exemplo, a reordenação de instruções para algo que é matematicamente o mesmo (idealmente), mas não exatamente o mesmo em ponto flutuante.

Segundo, ele desabilita a configuração de errno após funções matemáticas de instrução única, o que significa evitar uma gravação em uma variável de thread local (isso pode fazer uma diferença de 100% para essas funções em algumas arquiteturas).

Terceiro, faz-se a suposição de que toda matemática é finita , o que significa que nenhuma verificação de NaN (ou zero) é feita no lugar onde eles teriam efeitos prejudiciais. É simplesmente assumido que isso não vai acontecer.

Em quarto lugar, permite aproximações recíprocas para divisão e raiz quadrada recíproca.

Além disso, ele desabilita o zero assinado (o código assume que o zero assinado não existe, mesmo se o destino o suportar) e o arredondamento matemático, que permite, entre outras coisas, dobrar constantemente em tempo de compilation.

Por último, gera código que assume que nenhuma interrupção de hardware pode acontecer devido à sinalização / trapping de matemática (isto é, se eles não puderem ser desabilitados na arquitetura de destino e, consequentemente , acontecerem , eles não serão manipulados).