Lors de la lecture de Lua du code source, j'ai remarqué que Lua utilise un macro
à la ronde un double
32 bits int
. J'ai extrait l' macro
, et il ressemble à ceci:
union i_cast {double d; int i[2]};
#define double2int(i, d, t) \
{volatile union i_cast u; u.d = (d) + 6755399441055744.0; \
(i) = (t)u.i[ENDIANLOC];}
Ici, ENDIANLOC
est définie comme l'endianness, 0
pour little endian, 1
pour big endian. Lua soigneusement poignées boutisme. t
représente le type entier, comme int
ou unsigned int
.
J'ai fait une petite recherche et il y a un format plus simple d' macro
qui utilise la même pensée:
#define double2int(i, d) \
{double t = ((d) + 6755399441055744.0); i = *((int *)(&t));}
Ou en C++-style:
inline int double2int(double d)
{
d += 6755399441055744.0;
return reinterpret_cast<int&>(d);
}
Cette astuce peut travailler sur n'importe quel ordinateur à l'aide de la norme IEEE 754 (ce qui signifie à peu près toutes les machines d'aujourd'hui). Il fonctionne pour les nombres positifs et négatifs, et de l'arrondissement suit le Banquier est la Règle. (Ce n'est pas surprenant, car il suit la norme IEEE 754.)
J'ai écrit un petit programme pour tester:
int main()
{
double d = -12345678.9;
int i;
double2int(i, d)
printf("%d\n", i);
return 0;
}
Et c'sorties -12345679, comme prévu.
Je voudrais rentrer dans le détail comment cette délicate macro
travaux. La magie nombre 6755399441055744.0
est en fait 2^51 + 2^52
ou 1.5 * 2^52
, et 1.5
en binaire peut être représenté comme 1.1
. Lorsque l'un d'entier de 32 bits est ajouté à ce nombre magique, eh bien, je suis perdu à partir d'ici. Comment ce truc fonctionne?
P. S: C'est dans le code source en Lua, Llimits.h.
Mise à JOUR:
- @Mysticial points, cette méthode ne se limite pas à un 32-bit
int
, il peut également être étendu à un nombre de 64 bitsint
, tant que le nombre est en la gamme de 2^52. (macro
Besoin de quelques modifications.) - Certains matériaux de dire que cette méthode ne peut pas être utilisé en Direct3D.
-
Lorsque vous travaillez avec Microsoft assembleur x86, il y a une même plus rapide
macro
écrit enassembly
(ce qui est également extraites de Lua source):#define double2int(i,n) __asm {__asm fld n __asm fistp i}
Il y a une magie similaire numéro de simple précision nombre:
1.5 * 2 ^23