একটি ফ্লোটিং-পয়েন্ট হলো এমন একটি সংখ্যা, যার একটি ভগ্নাংশ অংশ থাকতে পারে, যেমন -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 |
৩২-বিট |
sd |
৬৪-বিট |
এই কনসেপ্টে উল্লিখিত কিছু নির্দেশ হলো:
| নির্দেশ | বিবরণ |
|---|---|
| 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 নামে একটি ফাংশন তৈরি করুন; রেটটি একটি ৬৪-বিট ফ্লোটিং-পয়েন্ট সংখ্যা।
চুক্তিতে বলা আছে, এক দিনে ৮ ঘণ্টার বিল করা যায়।
daily_rate(60)
// => 480.0
ফেরত দেওয়া দৈনিক রেটটি একটি ৬৪-বিট ফ্লোটিং-পয়েন্ট সংখ্যা হতে হবে।
ছাড়ের পরের দাম হিসাব করতে apply_discount নামে একটি ফাংশন তৈরি করুন।
এটি দুটি প্যারামিটার নেবে: আসল দাম এবং শতাংশে ছাড়ের হার, দুটোই ৬৪-বিট ফ্লোটিং-পয়েন্ট সংখ্যা।
apply_discount(150.0, 10.0)
// => 135.0
ফেরত দেওয়া মানটি সব সময় ৬৪-বিট ফ্লোটিং-পয়েন্ট সংখ্যা হতে হবে।
ছাড়ের পরের মাসিক রেট হিসাব করতে monthly_rate নামে একটি ফাংশন তৈরি করুন।
এটি দুটি প্যারামিটার নেয়: ঘণ্টার রেট এবং শতাংশে ছাড়, দুটোই ৬৪-বিট ফ্লোটিং-পয়েন্ট সংখ্যা।
monthly_rate(77.0, 10.5)
// => 12130
ফেরত দেওয়া মাসিক রেটটি নিকটতম ৬৪-বিট ইন্টিজারে রাউন্ড আপ করতে হবে (অর্থাৎ সিলিং নিতে হবে)।
days_in_budget নামে একটি ফাংশন তৈরি করুন, যা প্যারামিটার হিসেবে নেয়:
এই ফাংশনটি ফেরত দেবে বাজেটে কতগুলো পূর্ণ দিনের কাজ ধরে, সেই সংখ্যা।
days_in_budget(20000, 80, 11.0)
// => 35
ফেরত দেওয়া দিনের সংখ্যাটি নিকটতম ৩২-বিট ইন্টিজারে রাউন্ড ডাউন করতে হবে (অর্থাৎ ফ্লোর নিতে হবে)।
Exercism-এ সাইন আপ করুন, x86-64 Assembly ট্র্যাকের 22টি কনসেপ্ট130টি অনুশীলনী আর সত্যিকারের মানুষের মেন্টরিং দিয়ে শিখুন ও দক্ষ হয়ে উঠুন, সম্পূর্ণ বিনামূল্যে।