Pergunta

Eu tenho um projeto de software em que eu às vezes obter resultados estranhos de operações de ponto flutuante pequenas e simples. Eu supor que há algo que eu perdi, e gostaria de algumas dicas sobre como depurar os seguintes problemas:

(o compilador utilizado é o MS VC 6.0, que é a versão 12 do compilador Microsoft C)

Primeiro anomalia:

extern double Time, TimeStamp, TimeStep;  // History terms, updated elsewhere
void timer_evaluation_function( ) {
    if ( ( Time - TimeStamp ) >= TimeStep ) {  
        TimeStamp += TimeStep;  
        timer_controlled_code( );  
    }
{....}

Por alguma razão, a avaliação temporizador falhou eo código cronometrado não executado. No depurador, não havia nenhum problema para ver que a condição trig eram de fato verdade, mas o FPU recusou-se a encontrar um resultado positivo. O segmento de código a seguir não tinha problemas embora realizou as mesmas operações. O problema foi contornado através da inserção de uma avaliação falso que poderia ser permitido falhar.

Eu estou supondo que o estado FPU é de alguma forma contaminado por operações anteriores realizadas, e que há algumas bandeiras de compilador que iria ajudar?

Segundo anomalia:

double K, Kp = 1.0, Ti = 0.02;
void timed_code( ){
    K = ( Kp * ( float ) 2000 ) / ( ( float ) 2000 - 2.0F * Ti * 1e6 )
{....}

O resultado é #IND, embora o depurador avalia a equação para cerca de 0,05. O valor #IND aparece na pilha FPU quando o valor 2.0F é carregado na FPU de utilizar a instrução fld. As cargas de instrução anteriores o valor inteiro de 2000, como uma bóia dupla usando a instrução fild. Uma vez que a pilha FPU contém o valor #IND tudo está perdido, mas mais uma vez o depurador não tem nenhum problema avaliar a fórmula. Mais tarde, essas operações retornar os resultados esperados.

Além disso, mais uma vez os problemas FPU ocorrer diretamente após a chamada de função. Devo inserção de operações de ponto que limpa o estado FPU após cada nova função flutuante? Existe uma bandeira compilador que poderia afetar a FPU de alguma forma?

Sou grato de qualquer e todas as dicas e truques neste momento.

EDIT: eu consegui evitar o problema chamando a função de montagem Emms primeira coisa na função superior. Dessa forma, o FPU é limpa de qualquer lixo relacionado MMX que podem ou não podem ter sido criado no ambiente de meu código é chamado de. Parece que o estado da FPU não é algo para tomar para concedido.

// Frank

Foi útil?

Solução

Se você estiver usando as janelas QueryPerformanceCounter e funções QueryPerformanceFrequency em um sistema que suporta MMX tente inserir a instrução femms após consultar a frequência / balcão e antes da computação.

__asm femms

Eu encontrei problemas com estas funções antes de onde eles estavam fazendo a computação de 64 bits utilizando MMX e não limpar a flutuar bandeiras de ponto / estado.

Esta situação também pode acontecer se houver alguma aritmética de 64 bits entre as operações de ponto flutuante.

Outras dicas

Não faço ideia o que o problema poderia ser, mas em x86, as instruções FInit limpa a FPU. Para testar sua teoria, você pode inserir isso em algum lugar em seu código:

__asm {
    finit
}

Não é realmente uma resposta à sua pergunta, mas você pode querer olhar para dois dos artigos de Raymond Chen sobre o comportamento FPU estranho. Depois de ler sua pergunta e re-ler os artigos, eu não ver imediatamente um link - mas se o código que você colou não está completo ou se os artigos dar-lhe uma idéia sobre algum comportamento circundante que causou o problema .. . especificamente, se você está carregando uma DLL em qualquer lugar nas proximidades.

Uninitialized variáveis ??de ponto flutuante pode ser mortal

Como o ponto flutuante inválido operando exceção se levantou quando I desactivado?

Enquanto eu não estou fornecendo-lhe com uma solução exata, eu sugiro que você comece lendo este artigo que descreve as diferentes otimizações que se pode usar.

re: timestamps -

O que você está recebendo a sua fonte de timestamps de? Algo soa suspeito. Tente fazer login-los em um arquivo.

Se o valor ruim é carregado por um fld que deve ser carregado no 2.0, que eu iria verificar a memória onde este valor é carregado a partir -. Que poderia ser apenas um problema de compilador / vinculador

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