Qual é o propósito do boxe NaN?

44

Lendo século 21 C Eu cheguei no capítulo 6 na seção " Marcação de valores numéricos excepcionais com NaNs ", onde explica o uso dos bits na mantissa para armazenar alguns padrões de bits arbitrários, para usá-los como marcadores ou ponteiros (o livro menciona que o WebKit usa essa técnica ).

Eu não tenho certeza se entendi a utilidade dessa técnica, que eu vejo como um hack (depende do hardware não se importar com o valor da mantissa em um NaN), mas vindo de um background Java. não usado para a aspereza de C.

Aqui está o trecho de código que define e lê um marcador em um NaN

#include <stdio.h>
#include <math.h> //isnan

double ref;

double set_na(){
    if (!ref) {
        ref=0/0.;
        char *cr = (char *)(&ref);
        cr[2]='a';
    }
    return ref;
}

int is_na(double in){
    if (!ref) return 0;  //set_na was never called==>no NAs yet.

    char *cc = (char *)(&in);
    char *cr = (char *)(&ref);
    for (int i=0; i< sizeof(double); i++)
        if (cc[i] != cr[i]) return 0;
    return 1;
}

int main(){
    double x = set_na();
    double y = x;
    printf("Is x=set_na() NA? %i\n", is_na(x));
    printf("Is x=set_na() NAN? %i\n", isnan(x));
    printf("Is y=x NA? %i\n", is_na(y));
    printf("Is 0/0 NA? %i\n", is_na(0/0.));
    printf("Is 8 NA? %i\n", is_na(8));
}

imprime:

Is x=set_na() NA? 1
Is x=set_na() NAN? 1
Is y=x NA? 1
Is 0/0 NA? 0
Is 8 NA? 0

e em JSValue.h webkit explica a codificação, mas não porque é usado.

Qual é o propósito desta técnica? Os benefícios do espaço / desempenho são altos o suficiente para equilibrar sua natureza hackea?

    
por andijcr 31.01.2013 / 11:32
fonte

2 respostas

62

Quando você está implementando um idioma digitado dinamicamente, você precisa ter um único tipo que possa conter qualquer um dos seus objetos. Existem três abordagens diferentes que eu conheço para isso:

Em primeiro lugar, você pode passar ponteiros. É isso que a implementação do CPython faz. Todo objeto é um ponteiro PyObject . Esses ponteiros são passados e as operações são executadas observando os detalhes na estrutura PyObject para descobrir o tipo.

A desvantagem é que valores pequenos, como números, são armazenados como valores em caixa. Assim, seu pequeno 5 é armazenado como um bloco de memória em algum lugar. Isso nos leva à abordagem de união, que é usada por Lua. Em vez de um PyObject* , cada valor é uma estrutura que um campo para especificar o tipo e, em seguida, uma união de todos os diferentes tipos de suporte. Dessa forma, evitamos alocar memória para valores pequenos, em vez de armazená-los diretamente na união.

A abordagem NaN armazena tudo como duplas e reutiliza a parte não utilizada de NaN para o armazenamento extra. A vantagem sobre o método de união é que salvamos o campo type. Se é um duplo válido, é um duplo, caso contrário, a mantissa é um ponteiro para o objeto real.

Lembre-se, este é todo objeto javascript. Cada variável, todo valor em um objeto, toda expressão. Se pudermos reduzir todos aqueles de 96 bits para 64 bits, isso é bastante impressionante.

Vale a pena o hack? Lembre-se de que há muita demanda por JavaScript eficiente. Javascript é o gargalo em muitos aplicativos da Web e, portanto, torná-lo mais rápido é uma prioridade mais alta. É razoável introduzir um certo grau de imprevidência por motivos de desempenho. Para a maioria dos casos, seria uma má ideia, porque está introduzindo um grau de complexidade para pouco ganho. Mas, neste caso específico, vale a pena melhorar a memória e a velocidade.

    
por 31.01.2013 / 16:36
fonte
7

Usar NaN para "valores excepcionais" é uma técnica bem conhecida e às vezes útil para evitar a necessidade de uma variável booleana extra this_value_is_invalid . Usado sabiamente, ele pode ajudar a tornar seu código mais conciso, mais limpo, mais simples, melhor legível sem qualquer compromisso de desempenho.

Esta técnica tem algumas armadilhas, é claro (veja aqui link ), mas em linguagens como Java (ou C # muito similar) existem funções de biblioteca padrão como Float.isNaN para simplificar as operações com NaNs. Obviamente, em Java você poderia usar alternativamente a classe Float e Double e em C # os tipos de valor anuláveis float? e double? , dando a você a possibilidade de usar null em vez de NaN para números inválidos de ponto flutuante , mas essas técnicas podem ter uma influência negativa significativa no desempenho e uso de memória do seu programa.

Em C, o uso de NaN não é 100% portátil, é verdade, mas você pode usá-lo em qualquer lugar onde o padrão de ponto flutuante IEEE 754 esteja disponível. AFAIK isso é quase todo hardware convencional atualmente (ou pelo menos o ambiente de tempo de execução da maioria dos compiladores suporta isso). Por exemplo, esta postagem SO contém algumas informações para descobrir mais detalhes sobre o uso de NaN em C.

    
por 31.01.2013 / 15:54
fonte