เมื่ออ่านLua ของรหัสที่มาผมสังเกตเห็นว่า Lua ใช้macroในการออกรอบdoubleกับ int32 ฉันดึงข้อมูลmacroและดูเหมือนว่า:
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];}
ที่นี่ENDIANLOCถูกกำหนดให้เป็นendianness , 0สำหรับ endian เล็ก ๆ น้อย ๆ1สำหรับ endian ใหญ่ Lua จัดการกับ endianness อย่างระมัดระวัง tย่อมาจากชนิดจำนวนเต็มเช่นหรือintunsigned int
ฉันทำวิจัยเล็กน้อยและมีรูปแบบที่ง่ายกว่าmacroซึ่งใช้ความคิดเดียวกัน:
#define double2int(i, d) \
{double t = ((d) + 6755399441055744.0); i = *((int *)(&t));}
หรือในสไตล์ C ++:
inline int double2int(double d)
{
d += 6755399441055744.0;
return reinterpret_cast<int&>(d);
}
เคล็ดลับนี้สามารถทำงานกับเครื่องใด ๆ ที่ใช้IEEE 754 (ซึ่งหมายถึงทุกเครื่องในปัจจุบัน) มันทำงานสำหรับตัวเลขทั้งบวกและลบและการปัดเศษตามกฎของธนาคาร (สิ่งนี้ไม่น่าแปลกใจเนื่องจากเป็นไปตาม IEEE 754)
ฉันเขียนโปรแกรมเล็ก ๆ เพื่อทดสอบ:
int main()
{
double d = -12345678.9;
int i;
double2int(i, d)
printf("%d\n", i);
return 0;
}
และมันจะออกผลลัพธ์ -12345679 ตามที่คาดไว้
ฉันต้องการทราบรายละเอียดวิธีการmacroทำงานที่ซับซ้อนนี้ จำนวนมายากล6755399441055744.0เป็นจริง2^51 + 2^52หรือ1.5 * 2^52และในไบนารีสามารถแสดงเป็น1.5 1.1เมื่อเลขจำนวนเต็ม 32 บิตใด ๆ ถูกเพิ่มเข้าไปในจำนวนเวทย์มนตร์นี้ก็หายไปจากที่นี่ เคล็ดลับนี้ทำงานอย่างไร
PS: นี่คือในรหัสที่มา Lua, Llimits.h
อัปเดต :
- เนื่องจาก @Mysticial ชี้ให้เห็นวิธีการนี้ไม่ได้ จำกัด อยู่ที่ 32 บิต
intแต่ก็สามารถขยายได้ถึง 64 บิตintตราบใดที่ตัวเลขนั้นอยู่ในช่วง 2 ^ 52 (macroความต้องการการปรับเปลี่ยนบางอย่าง) - วัสดุบางอย่างบอกว่าวิธีนี้ไม่สามารถใช้ในDirect3Dได้
เมื่อทำงานกับ Microsoft Assembler สำหรับ x86 จะมีการ
macroเขียนที่เร็วขึ้นassembly(สิ่งนี้ยังแยกมาจากแหล่ง Lua):#define double2int(i,n) __asm {__asm fld n __asm fistp i}มีหมายเลขเวทย์มนตร์ที่คล้ายกันสำหรับหมายเลขความแม่นยำเดียว:
1.5 * 2 ^23
ftoiฉันสามารถดูได้ว่ามันจะเร็วกว่า แต่ถ้าคุณกำลังพูดถึง SSE ทำไมไม่ใช้แค่คำสั่งเดียวCVTTSD2SI?
double -> int64แน่นอนอยู่ใน2^52ช่วง สิ่งเหล่านี้เป็นเรื่องปกติโดยเฉพาะอย่างยิ่งเมื่อดำเนินการโน้มน้าวใจจำนวนเต็มโดยใช้ FFT ที่เป็นทศนิยม
