लुआ के स्रोत कोड को पढ़ते समय , मैंने देखा कि लुआ 32-बिट के macro
चक्कर लगाने के लिए एक का उपयोग करता है । मैंने निकाला , और यह इस तरह दिखता है:double
int
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
रूप में परिभाषित किया गया है , छोटे एंडियन के लिए, बड़े एंडियन के लिए। लुआ सावधानी से धीरज धरता है। पूर्णांक प्रकार के लिए खड़ा है, जैसे या ।0
1
t
int
unsigned int
मैंने थोड़ा शोध किया और इसका एक सरल प्रारूप है macro
जो समान विचार का उपयोग करता है:
#define double2int(i, d) \
{double t = ((d) + 6755399441055744.0); i = *((int *)(&t));}
या सी ++ में - शैली:
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-बिट पूर्णांक इस जादू की संख्या में जोड़ा जाता है, ठीक है, मैं यहाँ से खो गया हूं। यह ट्रिक कैसे काम करती है?
पुनश्च: यह Lua स्रोत कोड, Llimits.h में है ।
अद्यतन :
- जैसा कि @Mysticial बताते हैं, यह विधि केवल 32-बिट तक ही सीमित नहीं है
int
, इसे 64-बिटint
तक भी विस्तारित किया जा सकता है, जब तक कि यह संख्या 2 ^ 52 की सीमा में है। (macro
कुछ संशोधन की जरूरत है।) - कुछ सामग्रियों का कहना है कि इस विधि का उपयोग Direct3D में नहीं किया जा सकता है ।
जब Microsoft असेंबलर के साथ x86 के लिए काम कर रहा है, तो इसमें और भी तेज़ी से
macro
लिखा गया हैassembly
(यह लुआ स्रोत से भी निकाला गया है):#define double2int(i,n) __asm {__asm fld n __asm fistp i}
एकल सटीक संख्या के लिए एक समान मैजिक नंबर है:
1.5 * 2 ^23
ftoi
। लेकिन अगर आप एसएसई की बात कर रहे हैं, तो सिर्फ एक निर्देश का उपयोग क्यों न करें CVTTSD2SI
?
double -> int64
वास्तव में 2^52
सीमा के भीतर हैं । फ्लोटिंग-पॉइंट एफएफटी का उपयोग करते हुए पूर्णांक आक्षेप करते समय ये विशेष रूप से सामान्य हैं।