एक फ्लोटिंग-पॉइंट एक ऐसी संख्या है जिसका एक भिन्नात्मक भाग हो सकता है, जैसे -1.23 या 3.1415।
ऐसी संख्या को बाइट्स के क्रम के रूप में निरूपित करने के लिए x86-64 IEEE-754 मानक का उपयोग करता है। इस मानक में दो सबसे आम फॉर्मैट सिंगल-प्रिसीज़न फ्लोटिंग-पॉइंट और डबल-प्रिसीज़न फ्लोटिंग-पॉइंट संख्याएँ हैं। x86-64 दोनों का समर्थन करता है।
एक सिंगल-प्रिसीज़न फ्लोटिंग-पॉइंट संख्या 32-बिट चौड़ी होती है, जबकि एक डबल-प्रिसीज़न 64-बिट चौड़ी होती है।
x86-64 में फ्लोटिंग-पॉइंट अंकगणित करने के लिए 16 समर्पित रजिस्टर हैं, जिनके नाम xmm0 से xmm15 हैं।
ये रजिस्टर कम से कम 128-बिट चौड़े होते हैं, लेकिन नए प्रोसेसर इसे बढ़ाकर 256-बिट या 512-बिट कर देते हैं। लेकिन व्यवहार में, अधिकांश फ्लोटिंग-पॉइंट संख्याएँ इच्छित प्रिसीज़न के अनुसार सबसे नीचे वाले 32-बिट या 64-बिट का ही उपयोग करती हैं।
संख्या फॉर्मैट के बीच बदलने के लिए निर्देशों का एक समूह है: cvtxx2yy.
xx और yy दोनों ही लिटरल नहीं, बल्कि प्लेसहोल्डर हैं:
xx स्रोत ऑपरेंड के टाइप के लिए एक प्लेसहोल्डर है।yy गंतव्य ऑपरेंड के टाइप के लिए एक प्लेसहोल्डर है।यह प्लेसहोल्डर कई रूप ले सकता है, जिनमें शामिल हैं:
| प्लेसहोल्डर | अर्थ |
|---|---|
si |
चिह्नित पूर्णांक |
ss |
32-बिट फ्लोटिंग-पॉइंट |
sd |
64-बिट फ्लोटिंग-पॉइंट |
उदाहरण के लिए:
cvtsi2ss xmm0, eax ; converts a 32-bit signed integer to a single-precision floating-point
cvtsd2si rax, xmm1 ; converts a double-precision floating-point to a 64-bit signed integer
ध्यान दीजिए कि 32-बिट पूर्णांक को 64-बिट फ्लोटिंग-पॉइंट में या 64-बिट पूर्णांक को 32-बिट फ्लोटिंग-पॉइंट में बदलना संभव है।
इसी तरह, 32-बिट फ्लोटिंग-पॉइंट को 64-बिट पूर्णांक में या 64-बिट फ्लोटिंग-पॉइंट को 32-बिट पूर्णांक में बदलना भी संभव है।
दूसरे शब्दों में, एक cvtxx2yy में दोनों ऑपरेंड का आकार समान होना आवश्यक नहीं है:
cvtsi2sd xmm0, eax ; converts a 32-bit signed integer to a double-precision floating-point
cvtsi2ss xmm0, rax ; converts a 64-bit signed integer to a single-precision floating-point
cvtss2si rax, xmm0 ; converts a single-precision floating-point to a 64-bit signed integer
cvtsd2si eax, xmm0 ; converts a double-precision floating-point to a 32-bit signed integer
जब किसी फ्लोटिंग-पॉइंट संख्या को ठीक-ठीक पूर्णांक के रूप में व्यक्त नहीं किया जा सकता, तो cvtxx2si उस संख्या को mxcsr नाम के एक विशेष रजिस्टर में मौजूद राउंडिंग नियंत्रण के अनुसार राउंड कर देता है।
यह निकटतम तक राउंड, नीचे की ओर राउंड, ऊपर की ओर राउंड या ट्रंकेट हो सकता है।
फंक्शन में प्रवेश करते समय कोई डिफ़ॉल्ट निश्चित नहीं होता।
ध्यान दीजिए कि एक सटीक परिणाम राउंड नहीं होता और इसलिए राउंडिंग नियंत्रण का उस पर कोई असर नहीं पड़ता।
उदाहरण के लिए, 42.0 हमेशा 42 में बदला जाएगा।
इसी तरह के निर्देशों का एक समूह है जिसका फॉर्मैट cvttxx2si है (एक अतिरिक्त t के साथ) और जो हमेशा परिणाम को ट्रंकेट कर देता है।
roundxx निर्देशों का समूह स्रोत ऑपरेंड में मौजूद फ्लोटिंग-पॉइंट संख्या को राउंड करके गंतव्य ऑपरेंड में संग्रहीत कर देता है।
यहाँ, हमेशा की तरह, xx ऑपरेंड के टाइप के लिए एक प्लेसहोल्डर है: ss सिंगल-प्रिसीज़न के लिए और sd डबल-प्रिसीज़न फ्लोट के लिए।
ये निर्देश तीसरे ऑपरेंड के रूप में एक स्थिर संख्या लेते हैं। यह संख्या राउंडिंग मोड बताती है:
| संख्या | मोड |
|---|---|
| 0 | निकटतम |
| 1 | फ्लोर (नीचे) |
| 2 | सील (ऊपर) |
| 3 | ट्रंकेट |
उदाहरण के लिए:
roundss xmm0, xmm1, 1 ; this rounds down (takes the floor) a 32-bit floating-point in xmm1 and stores it in xmm0
roundsd xmm2, xmm2, 2 ; this rounds up (takes the ceil) a 64-bit floating-point in xmm2 and stores it in xmm2
चूँकि ये निर्देश एक सटीक परिणाम देते हैं, इनका उपयोग किसी cvtxx2si की तैयारी में किया जा सकता है।
फ्लोटिंग-पॉइंट संख्याओं के साथ किए जाने वाले कई ऑपरेशनों के लिए वही निर्देश होते हैं जो पूर्णांकों के लिए होते हैं, बस नाम के अंत में आवश्यक प्लेसहोल्डर (ss या sd) जोड़ दिया जाता है।
ये निर्देश दो-ऑपरेंड वाले होते हैं, सेमांटिक्स हमेशा की तरह की, यहाँ तक कि वे भी जो गुणा या भाग करते हैं:
addss xmm1, xmm2 ; xmm1 = xmm1 + xmm2 (all 32-bit floating-point)
mulsd xmm4, xmm5 ; xmm4 = xmm4 * xmm5 (all 64-bit floating-point)
divss xmm0, xmm3 ; xmm0 = xmm0 / xmm3 (all 32-bit floating-point)
एक XMM रजिस्टर से दूसरे में मान ले जाने वाले निर्देश movss या movsd हैं:
movss xmm1, xmm0 ; this copies a 32-bit floating-point from xmm0 to xmm1
movsd xmm6, xmm4 ; this copies a 64-bit floating-point from xmm4 to xmm6
किसी इमीडिएट (एक स्थिर चिह्नित पूर्णांक) को सीधे एक xmm रजिस्टर में ले जाना संभव नहीं है।
पहले इस संख्या को एक जनरल-पर्पज़ रजिस्टर में ले जाना होता है और फिर cvtsi2xx की मदद से बदलना होता है:
mov rax, 10 ; rax is a 64-bit integer with value 10
cvtsi2sd xmm0, rax ; xmm0 is a 64-bit floating-point with value 10.0
दो फ्लोटिंग-पॉइंट संख्याओं के बीच तुलना करने के लिए निर्देशों के दो समूह हैं।
इनका रूप comixx और ucomixx होता है, जहाँ xx या तो ss है या sd.
दोनों हमेशा की तरह rflags में फ्लैग सेट करते हैं, cmp के समान सेमांटिक्स के अनुसार।
इनके बीच अंतर यह है कि अगर दोनों फ्लोटिंग-पॉइंट संख्याओं में से किसी एक का मान NaN हो, तो ucomixx parity flag (PF) सेट करता है, जबकि ऐसी स्थिति में comixx एक एक्सेप्शन उठाता है।
फ्लोटिंग-पॉइंट मानों के बीच तुलना अचिह्नित होती है:
ucomisd xmm0, xmm1
ja .greater ; 'ja' must be used for "greater", not 'jg'
jb .lesser ; 'jb' must be used for "lesser", not 'jl'
System V ABI में, पहले आठ फ्लोटिंग-पॉइंट आर्गुमेंट फंक्शन को क्रम से, xmm0 से xmm7 तक पास किए जाते हैं।
फंक्शन से फ्लोटिंग-पॉइंट मान xmm0 में लौटाए जाते हैं और, अगर आवश्यक हो, तो xmm1 में।
सभी xmm रजिस्टर खुलकर उपयोग के लिए उपलब्ध हैं, इनमें से कोई भी कॉलर के लिए आरक्षित नहीं है।
फ्लोटिंग-पॉइंट मान मेमोरी में उसी आकार के पूर्णांकों के समान सेमांटिक्स के अनुसार परिभाषित किए जा सकते हैं। NASM (The Netwide Assembler - इस ट्रैक में इस्तेमाल होने वाला असेंबलर) फ्लोटिंग-पॉइंट मानों को वैज्ञानिक संकेतन में घोषित करने की सुविधा भी देता है।
section .data
pi dq 3.141592653589793 ; this is a double-precision floating-point value
exp_num dd 1.e5 ; this is a single precision floating-point value equal to 1 * 10⁵
exp_num2 dd 1.e+5 ; this is a single precision floating-point value equal to 1 * 10⁵
frac dq 1.e-10 ; this is a double precision floating-point value equal to 1 * 10⁻¹⁰, i.e., 0.0000000001
इस अभ्यास में आप ऐसा कोड लिखेंगे जो एक फ्रीलांसर को प्रोजेक्ट मैनेजर से बातचीत करने में मदद करेगा। आपको कुछ टूल बनाने हैं जिनसे दैनिक और मासिक दरें जल्दी से निकाली जा सकें, और चाहें तो दी गई छूट लगाकर भी।
सबसे पहले हम फ्रीलांसर और प्रोजेक्ट मैनेजर के बीच कुछ नियम तय कर लेते हैं:
कभी-कभी फ्रीलांसर अपनी दैनिक दर पर छूट देने की पेशकश करता है (जैसे अपने सबसे भरोसेमंद ग्राहकों के लिए या गैर-लाभकारी ग्राहकों के लिए)।
छूट को प्रतिशत दर्शाने वाली दशमलव संख्याओं के रूप में दर्शाया जाता है, जैसे 25.0 (25%)।
ये फ्लोटिंग-पॉइंट निर्देशों में लगने वाले प्रत्यय हैं:
| प्रत्यय | ऑपरेंड का आकार |
|---|---|
ss |
32-बिट |
sd |
64-बिट |
इस कॉन्सेप्ट में बताए गए कुछ निर्देश ये हैं:
| निर्देश | विवरण |
|---|---|
| movss/movsd a, b | b को a में कॉपी करता है |
| addss/addsd a, b | a = a + b |
| subss/subsd a, b | a = a - b |
| mulss/mulsd a, b | a = a * b |
| divss/divsd a, b | a = a / b |
| cvtsi2ss/cvtsi2sd a, b | पूर्णांक b को फ्लोटिंग-पॉइंट a में बदलता है |
| roundss/roundsd a, b, c | c के अनुसार फ्लोटिंग-पॉइंट b को राउंड करता है और a में संग्रहीत करता है |
| cvtss2si/cvtsd2si a, b | फ्लोटिंग-पॉइंट b को पूर्णांक a में बदलता है |
| comiss/comisd a, b | a और b की तुलना करता है, NaN होने पर एक्सेप्शन |
| ucomiss/ucomisd a, b | a और b की तुलना करता है, NaN होने पर PF सेट करता है |
roundss और roundsd में राउंडिंग के लिए ये कंट्रोल नंबर इस्तेमाल होते हैं:
| संख्या | मोड |
|---|---|
| 0 | निकटतम |
| 1 | फ्लोर (नीचे) |
| 2 | सील (ऊपर) |
| 3 | ट्रंकेट |
daily_rate नाम का एक फंक्शन बनाइए जो पैरामीटर में मिली प्रति घंटा दर से दैनिक दर निकाले। यह प्रति घंटा दर 64-बिट फ्लोटिंग-पॉइंट संख्या होती है।
नियम यह तय करता है कि एक दिन में 8 बिल योग्य घंटे होते हैं।
daily_rate(60)
// => 480.0
लौटाई गई दैनिक दर 64-बिट फ्लोटिंग-पॉइंट संख्या होनी चाहिए।
apply_discount नाम का फंक्शन बनाइए जो छूट लगने के बाद की कीमत निकाले।
इसे दो पैरामीटर मिलते हैं: मूल कीमत और प्रतिशत में छूट की दर। दोनों 64-बिट फ्लोटिंग-पॉइंट संख्याएँ होती हैं।
apply_discount(150.0, 10.0)
// => 135.0
लौटाई गई वैल्यू हमेशा 64-बिट फ्लोटिंग-पॉइंट संख्या होनी चाहिए।
monthly_rate नाम का फंक्शन बनाइए जो छूट लगाने के बाद की मासिक दर निकाले।
इसे दो पैरामीटर मिलते हैं: प्रति घंटा दर और प्रतिशत में छूट। दोनों 64-बिट फ्लोटिंग-पॉइंट संख्याएँ होती हैं।
monthly_rate(77.0, 10.5)
// => 12130
लौटाई गई मासिक दर को निकटतम 64-बिट पूर्णांक तक ऊपर की ओर राउंड करना चाहिए (सील लेना चाहिए)।
days_in_budget नाम का फंक्शन बनाइए जिसे पैरामीटर के रूप में ये चीज़ें मिलती हैं:
इस फंक्शन को उतने पूरे दिनों की संख्या लौटानी है जितने दिनों का काम यह बजट कवर करता है।
days_in_budget(20000, 80, 11.0)
// => 35
लौटाई गई दिनों की संख्या को निकटतम 32-बिट पूर्णांक तक नीचे की ओर राउंड करना चाहिए (फ्लोर लेना चाहिए)।
Exercism पर साइन अप कीजिए और x86-64 Assembly को 22 कॉन्सेप्ट130 अभ्यास तथा असली इंसानों से मिलने वाली मेंटरिंग के साथ सीखिए और उसमें महारत हासिल कीजिए, वह भी बिल्कुल मुफ्त।