Auto vetorização em dupla e ffast-math
-
27-09-2019 - |
Pergunta
Por que é obrigatório o uso de -ffast-math
com o g++ para alcançar a vetorização de loops usando double
s?Não gosto -ffast-math
porque eu não quero perder precisão.
Solução
Você não necessariamente perder precisão com -ffast-math
.Ele só afeta o tratamento de NaN
, Inf
etc.e a ordem em que as operações são executadas.
Se você tem um determinado trecho de código onde você não deseja GCC para reordenar ou simplificar os cálculos, você pode marcar as variáveis como sendo utilizados através de uma asm
instrução.
Por exemplo, o código a seguir executa uma operação de arredondamento f
.No entanto, os dois f += g
e f -= g
as operações são susceptíveis de obter optimizado para longe pelo gcc:
static double moo(double f, double g)
{
g *= 4503599627370496.0; // 2 ** 52
f += g;
f -= g;
return f;
}
No x86_64, você pode usar este asm
declaração para instruir o GCC não para executar a otimização:
static double moo(double f, double g)
{
g *= 4503599627370496.0; // 2 ** 52
f += g;
__asm__("" : "+x" (f));
f -= g;
return f;
}
Você terá de se adaptar a esta para cada arquitetura, infelizmente.Em PowerPC, use +f
em vez de +x
.
Outras dicas
Muito provavelmente porque a vetorização significa que você pode ter resultados diferentes ou pode significar que sente falta de sinais/exceções de ponto flutuante.
Se você estiver compilando para o X86 de 32 bits, o GCC e o G ++ padrão de usar o X87 para matemática de ponto flutuante, em 64 bits, eles são inadimplentes para o SSE, no entanto, o x87 pode e produzirá valores diferentes para o mesmo cálculo, por isso é improvável G ++ considerará a vetorização se não puder garantir que você obterá os mesmos resultados, a menos que use -ffast-math
Ou algumas das bandeiras que ela liga.
Basicamente, tudo se resume ao ambiente de ponto flutuante para o código vetorizado pode não ser o mesmo que o código não vetorizado, às vezes de maneiras importantes, se as diferenças não importam para você, algo como
-fno-math-errno -fno-trapping-math -fno-signaling-nans -fno-rounding-math
Mas, primeiro, procure essas opções e verifique se elas não afetarão a correção do seu programa. -ffinite-math-only
pode ajudar também
Porque -ffast-math
permite Operands reordenando que permite que muitos código sejam vetorizados.
Por exemplo, para calcular isso
sum = a[0] + a[1] + a[2] + a[3] + a[4] + a[5] + … a[99]
o compilador é requeridos Para fazer as adições sequencialmente sem -ffast-math
, porque a matemática de ponto flutuante não é comutativo nem associativo.
- A adição de pontos flutuantes é comutativa e associativa?
- A adição de ponto flutuante é comutativo em C ++?
- As operações de ponto flutuante são associativas C?
- A adição de pontos flutuantes e a multiplicação é associativa?
Esse é o mesmo motivo Por que os compiladores não podem otimizar a*a*a*a*a*a
para (a*a*a)*(a*a*a)
sem -ffast-math
Isso significa que nenhuma vetorização disponível, a menos que você tenha um vetor horizontal muito eficiente adicionado.
No entanto, se -ffast-math
está ativado, a expressão pode ser calculada assim (Olhe para A7. Auto-Vectorization
)
sum0 = a[0] + a[4] + a[ 8] + … a[96]
sum1 = a[1] + a[5] + a[ 9] + … a[97]
sum2 = a[2] + a[6] + a[10] + … a[98]
sum3 = a[3] + a[7] + a[11] + … a[99]
sum’ = sum0 + sum1 + sum2 + sum3
Agora, o compilador pode vetorizá -lo facilmente adicionando cada coluna em paralelo e depois fazer um add horizontal no final
Faz
sum’ == sum
? Somente se(a[0]+a[4]+…) + (a[1]+a[5]+…) + (a[2]+a[6]+…) + ([a[3]+a[7]+…) == a[0] + a[1] + a[2] + …
Isso se mantém sob associatividade, que os flutuos não aderem, o tempo todo. Especificação/fp:fast
Permite que o compilador transforme seu código para executar mais rápido - até 4 vezes mais rápido, para este cálculo simples.Você prefere rápido ou preciso? - A7. Vetorização automática
Pode ser ativado pelo -fassociative-math
Bandeira no GCC