Чтение 21-го века C Я пришел к главе 6 в разделе «Маркировка исключительных числовых значений с помощью NaN» , где объясняется использование битов в мантиссе для хранения некоторых произвольных битовых комбинаций, для их использования в качестве маркеров или указателей (упоминается в книге что 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 объясняет кодировку, но не почему она используется.
Какова цель этой техники? Достаточно ли высоки преимущества пространства / производительности, чтобы сбалансировать его хакерский характер?
источник
Ответы:
Когда вы реализуете динамически типизированный язык, у вас должен быть один тип, который может содержать любой из ваших объектов. Для этого есть три разных подхода:
Во-первых, вы можете обойти указатели. Это то, что делает реализация CPython. Каждый объект является
PyObject
указателем. Эти указатели передаются и операции выполняются путем просмотра деталей в структуре PyObject, чтобы выяснить тип.Недостатком является то, что маленькие значения, такие как числа, сохраняются как коробочные значения, поэтому ваши маленькие 5 хранятся где-то как блок памяти. Так что это приводит нас к объединенному подходу, который используется Lua. Вместо a
PyObject*
каждое значение представляет собой структуру, в которой одно поле должно указывать тип, а затем объединение всех различных поддерживаемых типов. Таким образом мы избегаем выделения памяти для небольших значений, вместо этого сохраняя их непосредственно в объединении.NaN
Подход хранит все , как удваивается, и повторно неиспользованную частьNaN
для дополнительного хранения. Преимущество перед методом объединения состоит в том, что мы сохраняем поле типа. Если это правильный double, это double, в противном случае мантисса является указателем на реальный объект.Помните, это каждый объект javascript. Каждая переменная, каждое значение в объекте, каждое выражение. Если мы сможем сократить все это с 96 до 64 бит, это будет довольно впечатляюще.
Это стоит взломать? Напомним, что существует большой спрос на эффективный Javascript. Javascript является узким местом во многих веб-приложениях, поэтому его ускорение является более высоким приоритетом. Разумно ввести определенную степень хакерства по соображениям производительности. В большинстве случаев это была бы плохая идея, потому что она вводит некоторую сложность за небольшую выгоду. Но в данном конкретном случае это стоит для улучшения памяти и скорости.
источник
SmallInteger
.Использование 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
упрощение работы с NaN. Конечно, в Java можно использовать в качестве альтернативы,Float
иDouble
класс , и в C # Если обнуляемые типов значенийfloat?
иdouble?
, давая вам возможность использоватьnull
вместо NaN для недействительных чисел с плавающей точкой, но эти методы могут оказать существенное негативное влияние на производительности и памяти использование вашей программы.В Си использование NaN не является переносимым на 100%, это правда, но вы можете использовать его везде, где доступен стандарт IEEE 754 с плавающей запятой. Насколько нам известно, это практически все основные аппаратные средства сегодня (или, по крайней мере, среда поддержки большинства компиляторов его поддерживает). Например, этот пост SO содержит некоторую информацию, чтобы узнать больше об использовании NaN в C.
источник