Pergunta

Estou escrevendo software numérico em tempo real, em C ++, atualmente compilando-o com o Visual-C ++ 2008. Agora, usando o modelo de ponto flutuante 'rápido' (/fp:fast), várias otimizações, a maioria úteis no meu caso, mas especificamente:

a/b -> a*(1/b) Division by multiplicative inverse

é numericamente instável demais para o A-Lot dos meus cálculos.

(Vejo: Microsoft Visual C ++ Otimização de ponto flutuante)

Mudando para /fp:precise Faz meu aplicativo funcionar mais do que duas vezes mais lento. É possível ajustar o otimizador (ou seja, desativar essa otimização específica) ou, de alguma forma, ignorá-lo manualmente?

- Exemplo real de código mínimo: -

void test(float a, float b, float c,
    float &ret0, float &ret1) {
  ret0 = b/a;
  ret1 = c/a;
} 

Meu código real é principalmente algoritmos relacionados à matriz

Saída: VC (CL, versão 15, 0x86) é:

divss       xmm0,xmm1 
mulss       xmm2,xmm0 
mulss       xmm1,xmm0 

Ter uma div, em vez de dois é um grande problema numericamente, (XMM0, é pré -carregado com 1,0F da RAM), como dependendo dos valores de XMM1,2 (que podem estar em diferentes faixas), você pode perder muita precisão ( Compilando sem SSE, produza o código Stack-X87-FPU semelhante).

Envolvendo a função com

#pragma float_control( precise, on, push )
...
#pragma float_control(pop)

Resolva o problema da precisão, mas, em primeiro lugar, ele só está disponível em um nível de função (escopo global) e, segundo, impede que a função (ou seja, as penalidades de velocidade são muito altas)

A saída 'precisa' está sendo lançada para 'dobrar' para frente e para trás como poço:

 divsd       xmm1,xmm2 
 cvtsd2ss    xmm1,xmm1 
 divsd       xmm1,xmm0 
 cvtpd2ps    xmm0,xmm1 
Foi útil?

Solução 5

(Estranha) Solução que encontrei: sempre que dividir o mesmo valor em uma função - adicione um pouco de epsilon:

    a/b; c/b 

->

    a/(b+esp1); c/(b+esp2)

Também salva você da div ocasional por zero

Outras dicas

Adicione o

#pragma float_control( precise, on)

antes do cálculo e

#pragma float_control( precise,off)

depois disso. Eu acho que isso deveria fazer isso.

Esse documento afirma que você pode controlar as otimizações de apontar float, de forma linha a linha, usando Pragmas.

Há também __assume. Você pode usar __assume (a/b! = (A*(1/b))). Na verdade, nunca usei __assume, mas, em teoria, existe exatamente para ajustar o otimizador.

Você pode colocar as funções que contêm esses cálculos em um arquivo de código -fonte separado e compilar apenas esse arquivo com as diferentes configurações?

Porém, não sei se isso é seguro, você precisará verificar!

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top