Por que double.NaN == double.NaN retorna false?

À primeira vista o programador poderia achar que a comparação acima resultaria em true, mas para surpresa da maioria (me incluindo) isso não ocorre. Será que é um bug da plataforma .NET?

Investigando a fundo a questão descobri que há uma especificação da IEEE que diz o seguinte:

“In the syntax of C , the predicate x != y is True but all others, x < y , x <= y , x == y , x >= y and x > y , are False whenever x or y or both are NaN.” (IEEE Standard 754 for Binary Floating-Point Arithmetic)

Então como proceder para descobrir se um valor é um NaN? O recomendado é usarmos double.IsNaN(double d). Mas o que exatamente essa função faz? Fiz o disassembly da mesma e pude constatar que ela simplesmente faz uso da definição da IEEE acima citada:

.method public hidebysig static bool IsNaN(float64 d) cil managed
{
.custom instance void System.Runtime.ConstrainedExecution.ReliabilityContractAttribute::.ctor(valuetype System.Runtime.ConstrainedExecution.Consistency, valuetype System.Runtime.ConstrainedExecution.Cer) = { int32(3) int32(2) }
.maxstack 8
L_0000: ldarg.0
L_0001: ldarg.0
L_0002: beq.s L_0006
L_0004: ldc.i4.1
L_0005: ret
L_0006: ldc.i4.0
L_0007: ret
}

Ou seja, realiza uma comparação do número com ele mesmo, se der false é porque o número é um NaN. Porém, para aqueles como eu, que estão “escovando bits” em busca de performance podemos fugir um pouco do recomendado e fazer a seguinte transformação:

double value = double.NaN;
if (double.IsNaN(value))
{
// faz algo
}

Em

double value = double.NaN;
if (value  != value)
{
// faz algo
}

Em testes realizados num dispositivo ARM rodando WindowsCE + .Net Compact Fremework 3.5 foi verificado que a value  != value é 2x mais rápido que double.IsNaN(value), o que pode ser justificado pelo fato de eliminarmos uma chamada à um método.

9 comments to Por que double.NaN == double.NaN retorna false?

  • Muito bom o post!
    Explicando um pouco o por que dessa grande mudança:
    -Vamos começar a fazer alguns posts técnicos sobre as tecnologias com as quais trabalhamos. Tentando esclarecer algumas dúvidas e expondo dificuldades, buscando ajudar no uso dessas tecnologias.

  • Jobson Ronan

    Guilherme,

    Uma solução mais simples para esse mísero ganho de performance seria se o compilador tornasse o método IsNaN em inline.

    Em uma pesquisa rápida li que apesar de não exister como forçar um método em C# a se tornar inline, o método se torna inline quando o JIT decide, e este normalmente toma boas decisões.

    Ou seja, tal alteração no código não seria uma grande melhoria. Mas em todo caso foi muito bom saber que double.NaN == double.NaN retorna false. E que é assim, basicamente, por definição.

    Abraços.

  • Guilherme Oliveira

    Jobson,
    O que você disse realmente vale para o “Full Framework”, mas para o caso do .Net Compact Framework isso parece ser um pouco diferente. Fiz benchmarks (não profiling, o que poderia não permitir o inline) e o resultado foi como eu falei: 2x mais rápido! Aparentemente o JIT do .Net CF não é tão bom quanto o do “Full Framework”…

    Abraços

  • É importante ressaltar que a otimização do “manual inline” do método foi feita por uma necessidade específica, baseada em métricas solidas, para um caso específico de uma linha de código que era chamada literalmente bilhões de vezes no caminho crítico (o trecho de código mais lento) do ciclo de operação mais frequente da nossa aplicação.

    No nosso caso, o ganho foi medido e não foi mísero, especificamente por causa das condições que expliquei acima. Em muitas outras aplicações, no entanto, essa otimização, com certeza, pode não ser o melhor caminho.

    Acho importante deixar claro pros leitores que a contribuição deste post não é “deixe de usar double.IsNan” e sim:

    1. Procure entender a fundo as coisas que você está trabalhando (busque definições, faça disassembly, etc)

    2. Tire métricas realistas do “antes e depois” de tudo que você está otimizando

    3. As vezes, não tenha medo de ousar e fazer uma coisa que “não faz sentido”. Inline de métodos REALMENTE deveria ser papel do JIT, não do programador. Pena que o do .NET compact, no device que estamos trabalhando, não tem essa capacidade.

  • oi, passei pra conhecer seu blog, e desejar boa semana
    bjss

    aguardo sua visita :)

  • I wish to express my respect for your generosity supporting men and ladies who need guidance on this one subject. Your unique commitment to finding the remedy all-around has been especially important and have all of the time produced those significantly like me to attain their objectives. Your wonderful important recommendations implies a lot a person like me and a entire lot far more to my office workers. Best wishes; from each 1 of us.

  • WONDERFUL Post.thanks for share..extra wait…

  • If some one wishes expert view regarding blogging afterward i advise him/her to pay a quick
    visit this weblog, Keep up the fastidious work.

  • I like your site so i respect your writing. I am a frequent visitor no doubt! How can I enroll in RSS?

Leave a Reply

 

 

 

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>