Entendo que o --ffast-math
sinalizador do gcc pode aumentar muito a velocidade das operações flutuantes e fica fora dos padrões do IEEE, mas não consigo encontrar informações sobre o que realmente está acontecendo quando está ligado. Alguém pode explicar alguns detalhes e talvez dar um exemplo claro de como algo mudaria se a bandeira estivesse ligada ou desligada?
Tentei pesquisar no SO para perguntas semelhantes, mas não consegui encontrar nada que explicasse o funcionamento do ffast-math.
double
, mas varia de acordo com a aplicação). Uma coisa a observar é que as otimizações rápidas de matemática não adicionam necessariamente "mais" arredondamentos. A única razão pela qual não é compatível com IEEE é porque a resposta é diferente (embora um pouco) do que está escrito.x
for menor que 10, o erro no exemplo do Mystical será reduzido em torno de 10 ^ -10. Mas sex = 10e20
, é provável que o erro seja muitos milhões.-fassociative-math
o que está incluído na-funsafe-math-optimizations
que por sua vez é ativado com-ffast-math
Por que não GCC otimizara*a*a*a*a*a
a(a*a*a)*(a*a*a)
?-ffast-math
faz muito mais do que apenas quebrar a conformidade estrita com o IEEE.Antes de tudo, é claro, ele quebra a estrita conformidade com o IEEE, permitindo, por exemplo, reordenar as instruções para algo que é matematicamente o mesmo (idealmente), mas não exatamente o mesmo no ponto flutuante.
Segundo, desabilita a configuração
errno
após funções matemáticas de instrução única, o que significa evitar a gravação em uma variável local de encadeamento (isso pode fazer uma diferença de 100% para essas funções em algumas arquiteturas).Terceiro, assume-se que toda a matemática é finita , o que significa que nenhuma verificação de NaN (ou zero) é feita no lugar onde eles teriam efeitos prejudiciais. Supõe-se simplesmente que isso não vai acontecer.
Quarto, permite aproximações recíprocas para divisão e raiz quadrada recíproca.
Além disso, ele desativa o zero assinado (o código assume que o zero assinado não existe, mesmo que o destino o suporte) e a matemática de arredondamento, que permite, entre outras coisas, dobrar constantemente no tempo de compilação.
Por fim, gera código que pressupõe que nenhuma interrupção de hardware possa ocorrer devido à matemática de sinalização / interceptação (ou seja, se elas não puderem ser desabilitadas na arquitetura de destino e, consequentemente , acontecerem , elas não serão tratadas).
fonte
-ffast-math
Define -fno-math-errno, -funsafe-math-optimizations, -ffinite-only-math, -fno-rounding-math, -fno-signaling -nans e -fcx-limited-range. Esta opção faz com que a macro FAST_MATH do pré-processador seja definida. "e algo da glibc, como (math.h
perto de math_errhandling)" Por padrão, todas as funções suportam manipulação de errno e exceção. No modo matemático rápido do gcc e se funções embutidas são definidas, isso pode não ser verdadeiro. "-ffast-math
permite ao compilador cortar alguns cantos e quebrar algumas promessas (como explicado), o que geralmente não é perigoso como tal e não é um problema para a maioria das pessoas. Para a maioria das pessoas, é o mesmo, apenas mais rápido. No entanto, se o seu código assumir e confiar nessas promessas, ele poderá se comportar de maneira diferente do esperado. Geralmente, isso significa que o programa parece funcionar bem, principalmente, mas alguns resultados podem ser "inesperados" (digamos, em uma simulação de física, dois objetos podem não colidir adequadamente).-O2
geralmente permite "toda" otimização legal, exceto aquelas que trocam tamanho por velocidade.-O3
também permite otimizações que trocam tamanho por velocidade. Ele ainda mantém 100% de correção.-ffast-math
tenta tornar as operações matemáticas mais rápidas, permitindo um comportamento "levemente incorreto", o que geralmente não é prejudicial, mas seria considerado incorreto pela redação do padrão. Se o código é realmente muito diferente em velocidade em dois compiladores (não apenas 1-2%), em seguida, verificar se o seu código é compatível rigorosamente as normas e ...#pragma omp parallel for
e, dentro do corpo do loop, você está lendo e escrevendo em endereços apontados por argumentos de função e realiza uma ramificação não trivial. Como um palpite sem instrução, você pode estar debulhando caches de dentro de sua chamada de threads definida pela implementação, e o MSVC pode evitar incorretamente repositórios intermediários que as regras de aliasing exigiriam. Impossível dizer.