Atualmente, estou trabalhando em um sistema de processamento numérico que será implantado em um ambiente crítico de desempenho. Ele recebe entradas na forma de matrizes numéricas (elas usam a eigen
biblioteca, mas, para os fins desta questão, talvez seja irrelevante) e executa uma série de cálculos numéricos (produtos matriciais, concatenações etc.) para produzir saídas.
Todas as matrizes são alocadas estaticamente e seus tamanhos são conhecidos em tempo de compilação. No entanto, algumas das entradas podem ser inválidas. Nesses casos excepcionais , ainda queremos que o código seja calculado e ainda queremos que saídas não "poluídas" por valores inválidos sejam usadas.
Para dar um exemplo, vamos dar o seguinte exemplo trivial (este é pseudo-código):
Matrix a = {1, 2, NAN, 4}; // this is the "input" matrix
Scalar b = 2;
Matrix output = b * a; // this results in {2, 4, NAN, 8}
A idéia aqui é que 2, 4 e 8 são valores utilizáveis, mas a NAN deve sinalizar ao destinatário dos dados que essa entrada esteve envolvida em uma operação que envolveu um valor inválido e deve ser descartada (isso será detectado através de um std::isfinite(value)
verifique antes que o valor seja usado).
Essa é uma maneira sólida de comunicar e propagar valores inutilizáveis, dado que o desempenho é crítico e a alocação de heap não é uma opção (e nem outras construções que consomem recursos, como boost::optional
ponteiros)?
Existem maneiras melhores de fazer isso? Neste ponto, estou bastante satisfeito com a configuração atual, mas esperava receber algumas idéias novas ou críticas produtivas da implementação atual.
Respostas:
Este é um caminho completamente razoável a seguir. Observe também que existem várias máscaras de bits que são interpretadas como NaN. Existem dois tipos principais de NaN: sinalização (que pode gerar uma exceção quando eles são criados, dependendo das configurações) e silencioso (o que nunca ocorre). Mesmo nos NaN silenciosos, no entanto, existem várias máscaras de bits que correspondem ao NaN silencioso. Se você quiser realmente se interessar, pode criar seus próprios NaNs que são diferentes dos NaNs regulares. Por exemplo, você pode usar um padrão de bits específico que corresponda a NA (que é um conceito diferente do NaN).
Quanto ao seu ponto sobre poluição. Isso fica muito mais complicado. Geralmente, qualquer operação matemática envolvendo NaN resulta em NaN. Em outras palavras, o NaN é contagioso. Em alguns casos, é isso que você deseja. Em outros, não é. Por exemplo, suponha que você tenha solicitado a média do vetor que você forneceu. É NaN, ou 7/3? O produto vetorial escalar * que você deu, no entanto, funcionará exatamente da maneira que você deseja, e você também não precisa fazer nenhuma
std::isfinite
verificação. Apenas multiplique os números e o NaN sairá automaticamente, para que tenha um bom desempenho. No entanto, se você deseja obter uma média de 7/3 para o seu vetor, precisa ser mais inteligente, porque fazê-lo ingenuamente resultará em NaN. Embora eu não saiba como fazer uma implementação rápida disso, o numpy tem um e seu código aberto, para que você possa ver isso.fonte
Parece bom para mim, desde que você tenha seu modelo de ponto flutuante fixo e tenha dito semântica NaN.
O IEEE 754 é suficiente no seu caso.
http://en.m.wikipedia.org/wiki/Single-precision_floating-point_format
/programming/5777484/how-to-check-if-c-compiler-uses-ieee-754-floating-point-standard
fonte