Membaca Abad 21 C Saya tiba di bab 6 di bagian "Menandai Nilai Numerik Luar Biasa dengan NaNs" , di mana ia menjelaskan penggunaan bit dalam mantissa untuk menyimpan beberapa pola bit sewenang-wenang, untuk menggunakannya sebagai marker atau pointer (buku ini menyebutkan bahwa WebKit menggunakan teknik ini).
Saya tidak begitu yakin saya mengerti kegunaan teknik ini, yang saya lihat sebagai peretasan (ini bergantung pada perangkat keras yang tidak peduli pada nilai mantissa dalam NaN) tetapi berasal dari latar belakang Java yang tidak biasa saya gunakan. kekasaran C.
Berikut ini potongan kode yang menetapkan dan membaca penanda di 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));
}
itu mencetak:
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
dan di webkit JSValue.h menjelaskan pengkodean, tetapi tidak mengapa itu digunakan.
Apa tujuan dari teknik ini? Apakah manfaat ruang / kinerja cukup tinggi untuk menyeimbangkan sifat peretasannya?
sumber
Jawaban:
Saat Anda menerapkan bahasa yang diketik secara dinamis, Anda harus memiliki satu jenis yang dapat menampung objek apa pun. Ada tiga pendekatan berbeda yang saya ketahui untuk ini:
Pertama, Anda bisa membagikan petunjuk. Inilah yang dilakukan oleh implementasi CPython. Setiap objek adalah
PyObject
pointer. Pointer ini dapat diedarkan dan operasi dilakukan dengan melihat detail pada struct PyObject untuk mengetahui tipe.Kerugiannya adalah bahwa nilai-nilai kecil seperti angka disimpan sebagai nilai kotak, Jadi 5 anak Anda disimpan sebagai blok memori di suatu tempat. Jadi ini membawa kita ke pendekatan persatuan, yang digunakan oleh Lua. Alih-alih
PyObject*
, setiap nilai adalah struct yang satu bidang untuk menentukan jenis, dan kemudian penyatuan semua jenis yang didukung berbeda. Dengan cara itu kami menghindari mengalokasikan memori apa pun untuk nilai-nilai kecil, alih-alih menyimpannya langsung di serikat.The
NaN
Pendekatan toko segala sesuatu sebagai ganda, dan menggunakan kembali bagian yang tidak terpakai dariNaN
untuk penyimpanan ekstra. Keuntungan dibandingkan metode penyatuan adalah kita menyimpan bidang tipe. Jika itu adalah dobel yang valid, itu adalah dobel jika tidak maka mantissa adalah sebuah pointer ke objek yang sebenarnya.Ingat, ini adalah setiap objek javascript. Setiap variabel, setiap nilai dalam suatu objek, setiap ekspresi. Jika kita bisa mengurangi semuanya dari 96 bit menjadi 64 bit, itu cukup mengesankan.
Apakah ini layak untuk diretas? Ingatlah bahwa ada banyak permintaan untuk Javascript yang efisien. Javascript adalah penghambat dalam banyak aplikasi web, dan membuatnya lebih cepat adalah prioritas yang lebih tinggi. Masuk akal untuk memperkenalkan tingkat peretasan tertentu untuk alasan kinerja. Untuk sebagian besar kasus, itu adalah ide yang buruk, karena memperkenalkan tingkat kerumitan untuk sedikit keuntungan. Namun dalam kasus khusus ini, bermanfaat untuk peningkatan memori dan kecepatan.
sumber
SmallInteger
.Menggunakan NaN untuk "nilai luar biasa" adalah teknik yang terkenal dan terkadang membantu untuk menghindari kebutuhan variabel boolean tambahan
this_value_is_invalid
. Digunakan dengan bijak, ini dapat membantu seseorang membuat kodenya lebih ringkas, lebih bersih, lebih sederhana, lebih mudah dibaca tanpa ada kompromi kinerja.Teknik ini memiliki beberapa jebakan, tentu saja (lihat di sini http://ppkwok.blogspot.co.uk/2012/11/java-cafe-1-never-write-nan-nan_24.html ), tetapi dalam bahasa seperti Jawa ( atau C # sangat mirip) ada fungsi perpustakaan standar ingin
Float.isNaN
membuat berurusan dengan NaNs sederhana. Tentu saja, di Jawa Anda bisa menggunakan alternatifFloat
danDouble
kelas dan di C # tipe nilai yang dapat dibatalkanfloat?
dandouble?
, memberi Anda kemungkinan menggunakannull
alih-alih NaN untuk angka floating point yang tidak valid, tetapi teknik-teknik tersebut dapat memiliki pengaruh negatif yang signifikan terhadap kinerja dan memori penggunaan program Anda.Dalam C penggunaan NaN tidak 100% portabel, itu benar, tetapi Anda dapat menggunakannya di mana-mana di mana standar titik mengambang IEEE 754 tersedia. AFAIK ini hampir setiap perangkat keras utama saat ini (atau setidaknya lingkungan runtime dari sebagian besar kompiler mendukungnya). Misalnya, pos SO ini berisi beberapa informasi untuk mengetahui detail lebih lanjut tentang penggunaan NaN dalam C.
sumber