Pergunta

Então eu tenho uma função que se parece com isto:

float function(){
    float x = SomeValue;
    return x / SomeOtherValue;
}

Em algum momento, esta função transborda e retorna um valor negativo muito grande.Para tentar rastrear exatamente onde isso estava acontecendo, adicionei uma instrução cout para que a função ficasse assim:

float function(){
    float x = SomeValue;
    cout << x;
    return x / SomeOtherValue;
}

e funcionou!Claro, resolvi completamente o problema usando um duplo.Mas estou curioso para saber por que a função funcionou corretamente quando a contei.Isso é típico ou pode haver um bug em algum outro lugar que estou perdendo?

(Se ajudar, o valor armazenado no float é apenas um valor inteiro, e não particularmente grande.Acabei de colocá-lo em um flutuador para evitar lançamento.)

Foi útil?

Solução

Bem-vindo ao maravilhoso mundo do ponto flutuante.A resposta obtida provavelmente dependerá do modelo de ponto flutuante com o qual você compilou o código.

Isso acontece devido à diferença entre a especificação IEEE e o hardware em que o código está sendo executado.Sua CPU provavelmente possui registros de ponto flutuante de 80 bits que são usados ​​para armazenar o valor flutuante de 32 bits.Isso significa que há muito mais precisão enquanto o valor permanece em um registrador do que quando ele é forçado para um endereço de memória (também conhecido como 'homing' do registrador).

Quando você passou o valor para cout, o compilador teve que escrever o ponto flutuante na memória, e isso resulta em perda de precisão e comportamento interessante em casos de overflow do WRT.

Consulte a documentação do MSDN sobre VC++ interruptores de ponto flutuante.Você poderia tentar compilar com /fp:strict e ver o que acontece.

Outras dicas

Imprimir um valor em cout não deve alterar o valor do parâmetro de forma alguma.

No entanto, tenho visto um comportamento semelhante: adicionar instruções de depuração causa uma alteração no valor.Nesses casos, e provavelmente neste também, meu palpite é que as instruções adicionais estavam fazendo com que o otimizador do compilador se comportasse de maneira diferente, portanto, gere um código diferente para sua função.

Adicionar a instrução cout significa que o valor de x é usado diretamente.Sem ele o otimizador poderia remover a variável, alterando assim a ordem do cálculo e, portanto, alterando a resposta.

Além disso, é sempre uma boa ideia declarar variáveis ​​imutáveis ​​usando const:

float function(){
    const float x = SomeValue;
    cout << x;
    return x / SomeOtherValue;
}

Entre outras coisas, isso impedirá que você passe involuntariamente suas variáveis ​​para funções que possam modificá-las através de métodos não-intencionais.const referências.

cout causa uma referência à variável, o que muitas vezes fará com que o compilador a force a despejá-la na pilha.

Por ser um float, isso provavelmente faz com que seu valor seja truncado da representação double ou long double que normalmente teria.

Chamar qualquer função (não embutida) que receba um ponteiro ou referência para x deve acabar causando o mesmo comportamento, mas se o compilador mais tarde ficar mais inteligente e aprender a incorporá-lo, você estará igualmente ferrado :)

Não creio que o cout tenha algum efeito na variável, o problema teria que estar em outro lugar.

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