Eine schnelle Methode, um ein Double zu einem 32-Bit-Int zu runden, wird erläutert

Beim Lesen Lua source code, habe ich gemerkt, dass Lua verwendet eine macro um eine double zu einem 32-bit -int. Ich extrahiert die macround es sieht wie folgt aus:

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];}

Hier ENDIANLOC ist definiert als endianness0 für little-endian, 1 für big endian. Lua sorgfältig verarbeitet endianness. t steht für den integer-Typ, wie int oder unsigned int.

Ich habe ein wenig Forschung und es gibt eine einfachere format macro verwendet den gleichen Gedanken:

#define double2int(i, d) \
    {double t = ((d) + 6755399441055744.0); i = *((int *)(&t));}

Oder in einem C++-style:

inline int double2int(double d)
{
    d += 6755399441055744.0;
    return reinterpret_cast<int&>(d);
}

Dieser trick kann funktionieren, auf jedem Rechner mit IEEE 754 (was bedeutet, dass so ziemlich jeder Maschine heute). Es funktioniert sowohl für positive und negative zahlen, und die Rundung folgt Banker ' s Rule. (Dies ist nicht überraschend, denn es folgt IEEE 754.)

Ich schrieb ein wenig Programm, um es zu testen:

int main()
{
    double d = -12345678.9;
    int i;
    double2int(i, d)
    printf("%d\n", i);
    return 0;
}

Ausgibt -12345679, wie erwartet.

Ich würde gerne ins detail, wie diese heikle macro funktioniert. Die Magische Zahl 6755399441055744.0 ist eigentlich 2^51 + 2^52 oder 1.5 * 2^52und 1.5 im Binär dargestellt werden kann, wie 1.1. Wenn jeder 32-bit-Ganzzahl wird Hinzugefügt, diese Magische Zahl, nun, ich bin verloren hier. Wie funktioniert dieser trick funktioniert?

P. S: Das ist in der Lua-Quellcode, Llimits.h.

UPDATE:

  1. Wie @Mysticial Punkte heraus, bei dieser Methode nicht begrenzen sich auf ein 32-bit -int
    es kann auch erweitert werden, um eine 64-bit - int solange die Zahl ist in
    der Wertebereich von 2^52. (Die macro braucht einige änderungen.)
  2. Einige Materialien, die sagen, diese Methode kann nicht verwendet werden,Direct3D.
  3. Beim arbeiten mit Microsoft assembler für x86, es ist ein noch
    schneller macro geschrieben assembly (dies ist auch extrahiert aus Lua-Quelle):

    #define double2int(i,n)  __asm {__asm fld n   __asm fistp i}
  4. Gibt es eine ähnliche Magische Zahl für single-precision-Nummer: 1.5 * 2 ^23

InformationsquelleAutor der Frage Yu Hao | 2013-06-11

Schreibe einen Kommentar