Pergunta

É uma boa ideia usar o ponto flutuante IEEE754 NaN (não um número) para valores indefinidos por razões não matemáticas?

No nosso caso eles ainda não estão configurados porque os valores não foram recebidos de algum outro dispositivo.O contexto é um sistema embarcado que utiliza valores IEC1131 REAL32. Editar: A linguagem de programação é C, então provavelmente usaríamos NAN e isnanf(x), que são de C99.Embora possamos precisar de algumas contorções extras para colocá-las em nossa camada de compatibilidade do sistema operacional.

O padrão nas linguagens de programação parece ser inicializar variáveis ​​de ponto flutuante com zero positivo, cuja representação interna é toda zero.Isso não é utilizável para nós, porque 0 está no intervalo de valores válidos.

Parece uma solução limpa para usar NaN, mas talvez seja mais complicado do que vale a pena e devêssemos escolher algum outro valor?

Foi útil?

Solução

Acabei de notar esta pergunta.

Este é um dos usos de NaNs que o comitê IEEE 754 tem em mente (fui membro do comitê).As regras de propagação para NaNs em aritmética tornam isso muito atraente, porque se você tiver um resultado de uma longa sequência de cálculos que envolvam alguns dados inicializados, você não confundirá o resultado com um resultado válido.Ele também pode tornar muito mais simples o rastreamento de seus cálculos para descobrir onde você está usando os dados inicializados.

Dito isto, existem algumas armadilhas que estão fora do controle do comitê 754:como outros observaram, nem todo hardware suporta valores NaN em velocidade, o que pode resultar em riscos de desempenho.Felizmente, muitas vezes não são realizadas muitas operações em dados inicializados em um ambiente de desempenho crítico.

Outras dicas

NaNs são uma escolha razoável para uma sentença 'sem valor' (a linguagem de programação D os utiliza para valores não inicializados, por exemplo), mas como quaisquer comparações envolvendo-os serão falsas, você pode ter algumas surpresas:

  • if (result == DEFAULT_VALUE), não funcionará como esperado se DEFAULT_VALUE é NaN, como Jon mencionou.

  • Eles também podem causar problemas na verificação de alcance se você não tomar cuidado.Considere a função:

bool isOutsideRange(double x, double minValue, double maxValue)
{
    return x < minValue || x > maxValue;
}

Se x for NaN, esta função reportará incorretamente que x está entre minValue e maxValue.

Se você deseja apenas um valor mágico para os usuários testarem, recomendo infinito positivo ou negativo em vez de NaN, pois ele não vem com as mesmas armadilhas.Use NaN quando quiser por sua propriedade de que qualquer operação em um NaN resulte em um NaN:é útil quando você não deseja depender da verificação do valor pelos chamadores, por exemplo.

[Editar:Inicialmente consegui digitar "quaisquer comparações envolvendo eles serão verdadeiras" acima, o que não foi o que eu quis dizer, e está errado, são todas falsas, exceto NaN! = NaN, que é verdade]

Eu usei NaNs em situações semelhantes apenas por causa disso:o valor de inicialização padrão usual 0 também é um valor válido.NaNs funcionam bem até agora.

A propósito, é uma boa pergunta por que o valor de inicialização padrão geralmente é (por exemplo, em tipos primitivos Java) 0 e não NaN.Não poderia ser 42 ou algo assim?Eu me pergunto qual é a lógica dos zeros.

Acho que é uma má ideia em geral.Uma coisa a ter em mente é que a maioria das CPUs tratam Nan muito mais lentamente do que a flutuação "normal".E é difícil garantir que você nunca terá Nan em ambientes normais.Minha experiência em computação numérica é que muitas vezes ela traz mais problemas do que vale a pena.

A solução correta é evitar codificar "ausência de valor" no float, mas sinalizá-la de outra forma.Porém, isso nem sempre é prático, dependendo da sua base de código.

Cuidado com os NaNs...eles podem se espalhar como um incêndio se você não tomar cuidado.

Eles são um valor perfeitamente válido para floats, mas quaisquer atribuições que os envolvam também serão iguais a NaN, portanto, eles se propagam pelo seu código.Isso é muito bom como uma ferramenta de depuração se você o pegar, mas também pode ser um verdadeiro incômodo se você estiver trazendo algo para lançar e houver um caso adicional em algum lugar.

D usa isso como justificativa para fornecer floats NaN como padrão.(Com o qual não tenho certeza se concordo.)

Minha impressão é que é um pouco hackeado, mas pelo menos todos os outros números que você faz operações com esse valor NaN fornecem NaN como resultado - quando você vê um NaN em um relatório de bug, pelo menos você sabe que tipo de erro está caçando.

Se sua necessidade básica é ter um valor de ponto flutuante que não represente nenhum número que possa ter sido recebido do dispositivo, e se o dispositivo garantir que nunca retornará NaN, então me parece razoável.

Apenas lembre-se de que dependendo do seu ambiente, você provavelmente precisará de uma maneira especial de detectar NaNs (não use apenas if (x == float.NaN) ou qualquer que seja o seu equivalente.)

Para mim, isso parece um bom uso para babás.Queria ter pensado nisso...

Claro, eles deveriam se propagar como um vírus, esse é o ponto.

Acho que usaria nan em vez de um dos infinitos.Pode ser bom usar um sinalizador e fazer com que ele cause um evento no primeiro uso, mas já é tarde demais e ele deve ficar silencioso no primeiro uso.

Usar NaN como valor padrão é razoável.

Observe que algumas expressões, como (0,0/0,0), retornam NaN.

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