Яка мета боксу NaN?


44

Читання 21 століття C Я прийшов до розділу 6 у розділі "Позначення виняткових числових значень з NaNs" , де пояснюється використання бітів у мантісі для зберігання деяких довільних бітових шаблонів, використання їх як маркерів чи покажчиків (книга згадується що WebKit використовує цю техніку).

Я не дуже впевнений, що зрозумів корисність цієї методики, що розглядаю як хак (він покладається на обладнання, яке не піклується про значення мантіси в NaN), але виходячи з тла Java, до якого я не звик шорсткість С.

Ось фрагмент коду, який встановлює та читає маркер у 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));
}

він друкує:

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

і на JSValue.h webkit пояснює кодування, але не чому він використовується.

Яке призначення цієї техніки? Чи достатньо високі переваги простору / продуктивності, щоб збалансувати його хакерський характер?


ви можете навести простий приклад?
BЈоviћ

щоб бути зрозумілим, ОП запитує, де можна використовувати сигналізаційні NaNs
храповик урод

1
@ratchetfreak, що змушує тебе це думати?
Вінстон Еверт

@ratchetfreak: питання не в тому, щоб сигналізувати про NaN, як пояснює webkit JSValue.h, але дякую, що дозволили мені відкрити щось нове!
andijcr

1
@Hudson isnan () si використовується в другому printf в основному. Метою is_an () є перевірити, чи бітова модель подвійного введення дорівнює тій, що зберігається всередині глобальної змінної ref.
andijcr

Відповіді:


63

Коли ви реалізуєте динамічно набрану мову, у вас повинен бути один тип, який може вміщувати будь-який із ваших об'єктів. Я знаю для цього три різні підходи:

По-перше, можна пройти навколо вказівників. Це те, що робить реалізація CPython. Кожен об’єкт - PyObjectпокажчик. Ці вказівники передаються навколо, і операції виконуються, переглядаючи деталі в структурі PyObject, щоб визначити тип.

Недоліком є ​​те, що невеликі значення, такі як числа, зберігаються у вигляді коробки, тож ваші маленькі 5 зберігаються десь як блок пам'яті. Отже, це призводить нас до союзного підходу, який використовує Луа. Замість а PyObject*, кожне значення - це структура, яке в одному полі вказати тип, а потім об'єднання всіх різних підтримуваних типів. Таким чином ми уникаємо виділення будь-якої пам'яті для малих значень, а замість цього зберігаємо їх безпосередньо в об'єднанні.

NaNПідхід зберігає всі , як подвоюється, і повторно невикористану частину NaNдля додаткового зберігання. Перевага перед методом об'єднання полягає в тому, що ми зберігаємо поле типу. Якщо це дійсний подвійний, це подвійний, інакше mantissa є вказівником на фактичний об'єкт.

Пам'ятайте, що це кожен об'єкт javascript. Кожна змінна, кожне значення в об'єкті, кожен вираз. Якщо ми можемо зменшити всі з 96 біт до 64 біт, це дуже вражає.

Варто зламати? Нагадаємо, що на ефективний Javascript існує великий попит. Javascript є вузьким місцем у багатьох веб-додатках, і тому його швидше є вищим пріоритетом. Розумно вводити певну ступінь хакерства з міркувань продуктивності. У більшості випадків це було б поганою ідеєю, оскільки введення ступеня складності для невеликої вигоди. Але в цьому конкретному випадку варто покращити пам’ять та швидкість.


2
Насправді CPython кешує невеликі числа. Дивіться hg.python.org/cpython/file/e6cc582cafce/Objects/longobject.c
Phillip Cloud

1
@cpcloud, правда, але ця деталь не здавалася доречною.
Вінстон Еверт

1
@WinstonEwert Ти маєш рацію. Я подумав те саме, що прочитав те, що написав.
Phillip Cloud

2
Використання бітів примітивного типу, щоб уникнути "боксу" всіх значень, - це техніка, що займається часом. Smalltalk використовував його в 1970-х, викрадаючи один біт з 16-бітових цілих чисел для передачі або вказівника об'єкта, або 15-бітного SmallInteger.
Джонатан Юніс

2
@JonathanEunice, справді? Це мене просто дивує, бо насправді не існує великого діапазону в 16 бітах, від якого я б хотів трохи відмовитись.
Вінстон Еверт

7

Використання NaN для "виняткових значень" - добре відома, а іноді і корисна методика, щоб уникнути необхідності додаткової булевої змінної this_value_is_invalid. Використовуючи розумно, він може допомогти зробити його код більш стислим, чистішим, простішим, кращим для читання без будь-яких компромісів щодо продуктивності.

Звичайно, ця методика має деякі підводні камені (див. Тут http://ppkwok.blogspot.co.uk/2012/11/java-cafe-1-never-write-nan-nan_24.html ), але мовами, такими як Java ( або дуже схожий на C #) є стандартні функції бібліотеки, як Float.isNaNспростити роботу з NaNs просто. Звичайно, в Java ви можете використовувати альтернативно Floatі Doubleclass, і в C # нульові типи значень, float?і double?, даючи вам можливість використовувати nullзамість NaN для недійсних чисел з плаваючою комою, але ці методи можуть мати істотний негативний вплив на продуктивність і пам'ять використання вашої програми.

У C використання NaN не є 100% портативним, це правда, але ви можете використовувати його всюди, де є стандарт IEEE 754 з плаваючою точкою. AFAIK - це майже практично кожне основне обладнання сьогодні (або принаймні середовище виконання більшості компіляторів підтримує це). Наприклад, ця публікація SO містить деяку інформацію, щоб дізнатися більше подробиць про використання NaN в C.


авто-бокс в Java брудний і його слід уникати, просто використовувати його , щоб бути в змозі забезпечити нульове значення смішно і схильною до помилок
тріскачки урод

я відредагував питання, щоб вказати, де webkit використовує NaN-бокс. Здається, що в веб-програмі використовується більш широке використання NaN, окрім як для сигналізації "NaN"
andijcr

2
@ratchetfreak: це підтверджує мою точку зору, звичайно
Doc Brown
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.