ভাসমান বস্তুর জন্য পাইথন উত্স কোডের একটি মন্তব্য স্বীকার করে যে:
তুলনা করা অনেকটা দুঃস্বপ্ন
কোনও পূর্ণসংখ্যার সাথে একটি ফ্লোটের তুলনা করার ক্ষেত্রে এটি বিশেষভাবে সত্য, কারণ, ফ্লোটের বিপরীতে পাইথনের পূর্ণসংখ্যা নির্বিচারে বড় হতে পারে এবং সর্বদা নির্ভুল হয়। পূর্ণসংখ্যাকে একটি ফ্লোটে কাস্ট করার চেষ্টা করা নির্ভুলতা হারাতে এবং তুলনাটি ভুল করে তুলতে পারে। কোনও পূর্ণসংখ্যার সাথে ভাসাটি কাস্ট করার চেষ্টা করা হয় না কারণ কোনও ভগ্নাংশের অংশ নষ্ট হবে।
এই সমস্যাটি পেতে, পাইথন একটি চেক সিরিজ করে, যদি কোনও চেক সফল হয় তবে ফলাফলটি ফিরিয়ে দেয় returning এটি দুটি মানের চিহ্নগুলির সাথে তুলনা করে, তারপরে পূর্ণসংখ্যাটি "ভীষণ বড়" কিনা ভাসমান হতে হবে, তারপরে ভাসমানটির ঘনকটিকে পূর্ণসংখ্যার দৈর্ঘ্যের সাথে তুলনা করে। যদি এই সমস্ত চেক ব্যর্থ হয় তবে ফলাফলটি পেতে তুলনামূলকভাবে দুটি নতুন পাইথন অবজেক্ট তৈরি করা প্রয়োজন।
যখন v
একটি পূর্ণসংখ্যার / দীর্ঘের সাথে একটি ফ্লোটের তুলনা করা হয় w
, তখন সবচেয়ে খারাপ পরিস্থিতি হ'ল:
v
এবং w
একই চিহ্ন রয়েছে (উভয় ইতিবাচক বা উভয় নেতিবাচক),
- পূর্ণসংখ্যার
w
কয়েকটি বিট থাকে যা এটি size_t
টাইপ করে রাখা যায় (সাধারণত 32 বা 64 বিট),
- পূর্ণসংখ্যার
w
কমপক্ষে 49 বিট থাকে,
- ভাসমানটির সূচকটি
v
বিটের সংখ্যার সমান w
।
এবং আমাদের প্রশ্নের মূল্যবোধের জন্য ঠিক এটিই রয়েছে:
>>> import math
>>> math.frexp(562949953420000.7) # gives the float's (significand, exponent) pair
(0.9999999999976706, 49)
>>> (562949953421000).bit_length()
49
আমরা দেখতে পাই যে 49 হ'ল ভাসমান এবং তার পূর্ণসংখ্যার বিটের সংখ্যা উভয়ই। উভয় সংখ্যা ইতিবাচক এবং তাই উপরের চারটি মানদণ্ড পূরণ করা হয়েছে।
মানগুলির মধ্যে একটিকে বৃহত্তর (বা আরও ছোট) বাছাই করা পূর্ণসংখ্যার বিটের সংখ্যা বা ব্যয়কারীর মান পরিবর্তন করতে পারে এবং তাই পাইথন ব্যয়বহুল চূড়ান্ত চেক না করে তুলনার ফলাফল নির্ধারণ করতে সক্ষম হয়।
এটি ভাষার সিপিথন বাস্তবায়নের জন্য নির্দিষ্ট।
আরও বিস্তারিতভাবে তুলনা
float_richcompare
ফাংশন দুটি মানের মধ্যে তুলনা পরিচালনা v
এবংw
।
নীচে ফাংশন সম্পাদন করে এমন চেকগুলির একটি ধাপে ধাপে বর্ণনা রয়েছে। পাইথন উত্সের মন্তব্যগুলি কার্যকারিতা কী তা বোঝার চেষ্টা করার সময় আসলে খুব সহায়ক হয়, তাই আমি প্রাসঙ্গিক যেখানে রেখেছি। আমি উত্তরগুলির পাদদেশে একটি তালিকাতে এই চেকগুলি সংক্ষিপ্তও করেছি।
মূল ধারণাটি পাইথন অবজেক্টস v
এবং w
দুটি উপযুক্ত সি ডাবলকে ম্যাপ করা i
এবং j
যা সঠিক ফলাফল দেওয়ার সাথে সহজেই তুলনা করা যায়। পাইথন 2 এবং পাইথন 3 উভয়ই এটি করতে একই ধারণা ব্যবহার করে (প্রাক্তন কেবলমাত্র পরিচালনা করে int
এবংlong
পৃথকভাবে প্রকারগুলি)।
করণীয় প্রথমটি v
যা নিশ্চিতভাবেই পাইথন ফ্লোট এবং এটি সি ডাবলে মানচিত্র করে i
। পরবর্তী ফাংশনটি ভাসমানটি কিনা তা দেখুন w
এবং এটি একটি সি ডাবলকে মানচিত্র করে j
। এটি সমস্ত ফাংশনটির জন্য সর্বোত্তম ক্ষেত্রে দৃশ্যমান কারণ অন্য সমস্ত চেক এড়ানো যায়। ফাংশন চেক কি না দেখার জন্য v
হয় inf
বা nan
:
static PyObject*
float_richcompare(PyObject *v, PyObject *w, int op)
{
double i, j;
int r = 0;
assert(PyFloat_Check(v));
i = PyFloat_AS_DOUBLE(v);
if (PyFloat_Check(w))
j = PyFloat_AS_DOUBLE(w);
else if (!Py_IS_FINITE(i)) {
if (PyLong_Check(w))
j = 0.0;
else
goto Unimplemented;
}
এখন আমরা জানি যে w
এই চেকগুলি ব্যর্থ হলে এটি পাইথন ফ্লোট নয়। এখন ফাংশনটি এটি একটি পাইথন পূর্ণসংখ্যা কিনা তা পরীক্ষা করে। যদি এটি হয় তবে সবচেয়ে সহজ পরীক্ষাটি হ'ল সাইন v
এবং এর চিহ্ন w
( 0
শূন্য হলে প্রত্যাবর্তন , -1
যদি নেতিবাচক হয়, 1
যদি ইতিবাচক হয়)) লক্ষণগুলি পৃথক হলে, তুলনার ফলাফলটি ফেরত দেওয়ার জন্য প্রয়োজনীয় সমস্ত তথ্য:
else if (PyLong_Check(w)) {
int vsign = i == 0.0 ? 0 : i < 0.0 ? -1 : 1;
int wsign = _PyLong_Sign(w);
size_t nbits;
int exponent;
if (vsign != wsign) {
/* Magnitudes are irrelevant -- the signs alone
* determine the outcome.
*/
i = (double)vsign;
j = (double)wsign;
goto Compare;
}
}
যদি এই চেকটি ব্যর্থ হয়, তবে v
এবং w
একই চিহ্ন রয়েছে।
পরবর্তী চেকটি পূর্ণসংখ্যার বিটের সংখ্যা গণনা করে w
। যদি এর মধ্যে অনেকগুলি বিট থাকে তবে সম্ভবত এটি একটি ফ্লোট হিসাবে ধরে রাখা যায় না এবং তাই অবশ্যই ভাসমানের চেয়ে প্রস্থে আরও বড় হতে হবে v
:
nbits = _PyLong_NumBits(w);
if (nbits == (size_t)-1 && PyErr_Occurred()) {
/* This long is so large that size_t isn't big enough
* to hold the # of bits. Replace with little doubles
* that give the same outcome -- w is so large that
* its magnitude must exceed the magnitude of any
* finite float.
*/
PyErr_Clear();
i = (double)vsign;
assert(wsign != 0);
j = wsign * 2.0;
goto Compare;
}
অন্যদিকে, যদি পূর্ণসংখ্যার w
48 বা তার কম বিট থাকে তবে এটি নিরাপদে সি ডাবলে পরিণত হতে পারে j
এবং তুলনা করতে পারে :
if (nbits <= 48) {
j = PyLong_AsDouble(w);
/* It's impossible that <= 48 bits overflowed. */
assert(j != -1.0 || ! PyErr_Occurred());
goto Compare;
}
এই দিক থেকে, আমরা জানি যে w
49 বা তার বেশি বিট রয়েছে has এটি w
ইতিবাচক পূর্ণসংখ্যার হিসাবে বিবেচনা করা সুবিধাজনক হবে , সুতরাং সাইন এবং তুলনা অপারেটরটিকে প্রয়োজনীয় হিসাবে পরিবর্তন করুন:
if (nbits <= 48) {
/* "Multiply both sides" by -1; this also swaps the
* comparator.
*/
i = -i;
op = _Py_SwappedOp[op];
}
এখন ফাংশনটি ভাসমানটির সূচকটি দেখায়। স্মরণ করুন যে একটি ভাসাটি 2 চিহ্ন হিসাবে তাত্পর্যপূর্ণ হিসাবে চিহ্ন (উপেক্ষা) রচনা করা যায় এবং তা হ'ল 0.5 এবং 1 এর মধ্যে একটি সংখ্যা উপস্থাপন করে:
(void) frexp(i, &exponent);
if (exponent < 0 || (size_t)exponent < nbits) {
i = 1.0;
j = 2.0;
goto Compare;
}
এটি দুটি জিনিস পরীক্ষা করে। যদি কাফেরটি 0 এর চেয়ে কম হয় তবে ভাসমানটি 1 এর চেয়ে ছোট (এবং কোনও পূর্ণসংখ্যার তুলনায় প্রস্থে এত ছোট)। বা, যদি ব্যয়কৃত বিটের সংখ্যার চেয়ে কম হয় w
তবে আমাদের কাছে v < |w|
যেহেতু তাত্পর্যপূর্ণ * 2 এক্সপোনেন্টটি 2 নবিট কম ।
এই দুটি চেক ব্যর্থ হয়ে, ফাংশনটি বিট সংখ্যার চেয়ে এক্সপোনেন্টটি বেশি কিনা তা দেখতে দেখায় w
। এ থেকে জানা যায় significand * 2 এক্সপোনেন্ট 2 চেয়ে বেশী nbits এবং তাই v > |w|
:
if ((size_t)exponent > nbits) {
i = 2.0;
j = 1.0;
goto Compare;
}
যদি এই চেকটি সফল না হয় তবে আমরা জানি যে ভাসমানটির সূচকটি v
পূর্ণসংখ্যার বিটের সংখ্যার সমান w
।
একমাত্র উপায় যে দুটি মান এখন তুলনা করা যেতে পারে থেকে দুটি নতুন পাইথন পূর্ণসংখ্যার গঠন করা হয় v
এবং w
। ধারণাটি হ'ল ভগ্নাংশের অংশটি ফেলে দেওয়া v
, পূর্ণসংখ্যার অংশটি দ্বিগুণ করা এবং তারপরে একটি যুক্ত করা। w
দ্বিগুণও হয় এবং এই দুটি নতুন পাইথন অবজেক্টকে সঠিক ফেরতের মান দেওয়ার সাথে তুলনা করা যেতে পারে। ছোট মান সহ একটি উদাহরণ ব্যবহার 4.65 < 4
করে, তুলনা (2*4)+1 == 9 < 8 == (2*4)
(মিথ্যা প্রত্যাবর্তন) দ্বারা নির্ধারিত হবে ।
{
double fracpart;
double intpart;
PyObject *result = NULL;
PyObject *one = NULL;
PyObject *vv = NULL;
PyObject *ww = w;
// snip
fracpart = modf(i, &intpart); // split i (the double that v mapped to)
vv = PyLong_FromDouble(intpart);
// snip
if (fracpart != 0.0) {
/* Shift left, and or a 1 bit into vv
* to represent the lost fraction.
*/
PyObject *temp;
one = PyLong_FromLong(1);
temp = PyNumber_Lshift(ww, one); // left-shift doubles an integer
ww = temp;
temp = PyNumber_Lshift(vv, one);
vv = temp;
temp = PyNumber_Or(vv, one); // a doubled integer is even, so this adds 1
vv = temp;
}
// snip
}
}
ব্রিভিটির জন্য আমি অতিরিক্ত ত্রুটি-চেকিং এবং আবর্জনা-ট্র্যাকিংয়ের কথা বাদ দিয়েছি যখন পাইথন এই নতুন অবজেক্ট তৈরি করে তখন তা করতে হবে। বলা বাহুল্য, এটি অতিরিক্ত ওভারহেড যুক্ত করে এবং ব্যাখ্যা করেছে যে কেন প্রশ্নে হাইলাইট করা মানগুলি অন্যের তুলনায় তুলনামূলকভাবে ধীরে ধীরে কম।
তুলনা ফাংশন দ্বারা সম্পাদিত চেকগুলির সংক্ষিপ্তসার এখানে দেওয়া হল।
আসুন v
একটি ভাসা এবং এটি সি ডাবল হিসাবে কাস্ট করুন। এখন, যদি w
ভাসাও হয়:
তা পরীক্ষা করুন w
হয় nan
বা inf
। যদি তা হয় তবে ধরণের ধরণের উপর নির্ভর করে এই বিশেষ কেসটিকে আলাদাভাবে পরিচালনা করুন w
।
যদি তা না হয় তবে সি ডাবল হিসাবে তাদের উপস্থাপনা দ্বারা তুলনা করুন v
এবং w
সরাসরি করুন ।
যদি w
পূর্ণসংখ্যা হয়:
লক্ষণ এক্সট্র্যাক্ট v
এবং w
। যদি সেগুলি পৃথক হয় তবে আমরা জানি v
এবং w
পৃথক এবং কোনটি বৃহত্তর।
( লক্ষণগুলি একই )) w
ভাসমান হতে অনেকগুলি বিট রয়েছে কিনা তা পরীক্ষা করুন (তার চেয়ে বেশি size_t
)। যদি তাই হয় তবে w
এর চেয়ে বেশি মাত্রা রয়েছে v
।
w
48 বা কম বিট আছে কিনা তা পরীক্ষা করুন । যদি তা হয় তবে এটি নির্ভুলতা না হারিয়ে নিরাপদে সি ডাবলে ফেলে দেওয়া যায় এবং এর সাথে তুলনা করা যায় v
।
( w
48 টিরও বেশি বিট রয়েছে। এখন w
তুলনামূলক বিকল্পটি যথাযথ হিসাবে পরিবর্তন করে আমরা ইতিবাচক পূর্ণসংখ্যার হিসাবে বিবেচনা করব ))
ভাসমানটির উদ্দীপক বিবেচনা করুন v
। তাহলে এক্সপোনেন্ট নেতিবাচক হয়, তাহলে v
কম 1
কোনো ধনাত্মক পূর্ণসংখ্যা চেয়ে এবং সেইজন্য কম। অন্যথায়, যদি বিট সংখ্যার তুলনায় বেদীটি কম হয় w
তবে অবশ্যই এটির চেয়ে কম হওয়া উচিত w
।
তাহলে এর এক্সপোনেন্ট v
বিট সংখ্যার চেয়ে বেশী w
তারপর v
চেয়ে বেশী w
।
( এক্সপোনেন্ট বিট সংখ্যা হিসাবে একই w
। )
চূড়ান্ত চেক। v
এর পূর্ণসংখ্যা এবং ভগ্নাংশের মধ্যে বিভক্ত করুন । ভগ্নাংশের অংশটি ক্ষতিপূরণ করতে পূর্ণসংখ্যার অংশটি দ্বিগুণ করুন এবং 1 যুক্ত করুন। এখন পূর্ণসংখ্যা দ্বিগুণ করুন w
। ফলাফল পাওয়ার পরিবর্তে এই দুটি নতুন পূর্ণসংখ্যার তুলনা করুন।