¿Cuál es el propósito del boxeo de NaN?

44

Leyendo Siglo XXI C Llegué al capítulo 6 en la sección " Marcado de valores numéricos excepcionales con NaNs ", donde explica el uso de los bits en la mantisa para almacenar algunos patrones de bits arbitrarios, para usarlos como marcadores o indicadores (el libro menciona que WebKit usa esta técnica ).

No estoy realmente seguro de haber entendido la utilidad de esta técnica, que veo como un truco (se basa en que el hardware no se preocupa por el valor de la mantisa en un NaN) pero proviene de un fondo Java. no acostumbrado a la rugosidad de C.

Aquí está el fragmento de código que establece y lee un marcador en un 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));
}

se 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

y en

¿Cuál es el propósito de esta técnica? ¿Son los beneficios de espacio / rendimiento lo suficientemente altos como para equilibrar su naturaleza hackish?

    
pregunta andijcr 31.01.2013 - 11:32

2 respuestas

62

Cuando implementas un lenguaje de tipo dinámico, debes tener un solo tipo que pueda contener cualquiera de tus objetos. Hay tres enfoques diferentes que conozco para esto:

En primer lugar, puedes pasar los punteros. Esto es lo que hace la implementación de CPython. Cada objeto es un puntero PyObject . Estos punteros se pasan y las operaciones se realizan observando los detalles en la estructura PyObject para averiguar el tipo.

La desventaja es que los valores pequeños como los números se almacenan como valores en recuadros, por lo que sus 5 pequeños se almacenan como un bloque de memoria en algún lugar. Así que esto nos lleva al enfoque sindical, que es usado por Lua. En lugar de un PyObject* , cada valor es una estructura en la que un campo especifica el tipo, y luego una unión de todos los diferentes tipos compatibles. De esa manera, evitamos asignar cualquier memoria para valores pequeños, en lugar de almacenarlos directamente en la unión.

El enfoque NaN almacena todo como se duplica y reutiliza la porción no utilizada de NaN para el almacenamiento adicional. La ventaja sobre el método de unión es que guardamos el campo de tipo. Si es un doble válido, es un doble; de lo contrario, la mantisa es un puntero al objeto real.

Recuerda, esto es todo objeto javascript. Cada variable, cada valor en un objeto, cada expresión. Si podemos reducir todos esos de 96 bits a 64 bits, eso es bastante impresionante.

¿Vale la pena el hack? Recuerde que hay una gran demanda de Javascript eficiente. Javascript es el cuello de botella en muchas aplicaciones web, por lo que aumentar la velocidad es una prioridad más alta. Es razonable introducir cierto grado de piratería por razones de rendimiento. Para la mayoría de los casos, sería una mala idea, ya que está introduciendo un cierto grado de complejidad con poco beneficio. Pero en este caso específico, vale la pena para mejorar la memoria y la velocidad.

    
respondido por el Winston Ewert 31.01.2013 - 16:36
7

El uso de NaN para "valores excepcionales" es una técnica bien conocida y, a veces, útil para evitar la necesidad de una variable booleana adicional this_value_is_invalid . Utilizado de manera inteligente, puede ayudar a que su código sea más conciso, más limpio, más sencillo y más legible sin ningún tipo de compromiso de rendimiento.

Esta técnica tiene algunos inconvenientes, por supuesto (consulte aquí enlace ), pero en lenguajes como Java (o C # muy similar) hay funciones estándar de biblioteca como Float.isNaN para hacer que el manejo de las NaN sea simple. Por supuesto, en Java puede usar alternativamente las clases Float y Double y en C # los tipos de valores que admiten nulos float? y double? , lo que le da la posibilidad de usar null en lugar de NaN para números de punto flotante no válidos , pero esas técnicas pueden tener una influencia negativa significativa en el rendimiento y el uso de memoria de su programa.

En C, el uso de NaN no es 100% portátil, es cierto, pero puede usarlo en cualquier lugar donde esté disponible el estándar de punto flotante IEEE 754. AFAIK es casi todo el hardware principal de la actualidad (o al menos el entorno de ejecución de la mayoría de los compiladores lo admite). Por ejemplo, esta publicación de SO contiene información para descubrir Más detalles sobre el uso de NaN en C.

    
respondido por el Doc Brown 31.01.2013 - 15:54

Lea otras preguntas en las etiquetas