اصلی اقسام کی غیر حقیقی خصوصیات، یا REAL سے محتاط رہیں

اشاعت کے بعد مضامین PostgreSQL میں ٹائپنگ کی خصوصیات کے بارے میں، پہلا تبصرہ حقیقی نمبروں کے ساتھ کام کرنے کی مشکلات کے بارے میں تھا۔ میں نے اپنے پاس دستیاب SQL سوالات کے کوڈ پر ایک سرسری نظر ڈالنے کا فیصلہ کیا تاکہ یہ معلوم ہو سکے کہ وہ کتنی بار REAL قسم کا استعمال کرتے ہیں۔ یہ پتہ چلتا ہے کہ یہ اکثر استعمال کیا جاتا ہے، اور ڈویلپرز ہمیشہ اس کے پیچھے خطرات کو نہیں سمجھتے ہیں. اور یہ اس حقیقت کے باوجود کہ انٹرنیٹ پر اور Habré پر کمپیوٹر میموری میں حقیقی نمبروں کو محفوظ کرنے اور ان کے ساتھ کام کرنے کی خصوصیات کے بارے میں کافی اچھے مضامین موجود ہیں۔ لہذا، اس مضمون میں میں پوسٹگری ایس کیو ایل پر اس طرح کے فیچرز کو لاگو کرنے کی کوشش کروں گا، اور ان سے جڑی پریشانیوں پر ایک سرسری نظر ڈالنے کی کوشش کروں گا، تاکہ ایس کیو ایل استفسار کرنے والوں کے لیے ان سے بچنا آسان ہو جائے۔

PostgreSQL دستاویزات میں مختصراً کہا گیا ہے: "اس طرح کی غلطیوں کا انتظام اور حساب کے دوران ان کا پھیلاؤ ریاضی اور کمپیوٹر سائنس کی ایک پوری شاخ کا موضوع ہے، اور یہاں اس کا احاطہ نہیں کیا گیا ہے" (جبکہ دانشمندی کے ساتھ قاری کو IEEE 754 معیار کی طرف رجوع کیا گیا ہے)۔ یہاں کس قسم کی غلطیاں مراد ہیں؟ آئیے ان پر ترتیب وار گفتگو کرتے ہیں، اور جلد ہی یہ واضح ہو جائے گا کہ میں نے دوبارہ قلم کیوں اٹھایا۔

آئیے مثال کے طور پر ایک سادہ سی درخواست لیتے ہیں:

********* ЗАПРОС *********
SELECT 0.1::REAL;
**************************
float4
--------
    0.1
(1 строка)

نتیجے کے طور پر، ہمیں کچھ خاص نظر نہیں آئے گا - ہمیں متوقع 0.1 ملے گا۔ لیکن اب آئیے اس کا موازنہ 0.1 سے کریں:

********* ЗАПРОС *********
SELECT 0.1::REAL = 0.1;
**************************
?column?
----------
f
(1 строка)

برابر نہیں! کیا معجزات ہیں! لیکن مزید، مزید. کوئی کہے گا، میں جانتا ہوں کہ REAL مختلف حصوں کے ساتھ برا برتاؤ کرتا ہے، اس لیے میں وہاں پورے نمبر درج کروں گا، اور ان کے ساتھ یقینی طور پر سب کچھ ٹھیک ہو جائے گا۔ ٹھیک ہے، آئیے REAL پر نمبر 123 کاسٹ کریں:

********* ЗАПРОС *********
SELECT 123456789::REAL::INT;
**************************
   int4   
-----------
123456792
(1 строка)

اور یہ 3 مزید نکلے! بس، ڈیٹا بیس آخر کار گننے کا طریقہ بھول گیا! یا ہم کچھ غلط سمجھ رہے ہیں؟ آئیے اس کا پتہ لگائیں۔

سب سے پہلے، مواد کو یاد رکھیں. جیسا کہ آپ جانتے ہیں، کسی بھی اعشاریہ نمبر کو دس کی طاقتوں میں بڑھایا جا سکتا ہے۔ تو، نمبر 123.456 1*102 + 2*101 + 3*100 + 4*10-1 + 5*10-2 + ​​6*10-3 کے برابر ہوگا۔ لیکن کمپیوٹر نمبرز کے ساتھ بائنری شکل میں کام کرتا ہے، اس لیے انہیں دو کی طاقتوں میں توسیع کی صورت میں ظاہر کرنا ہوگا۔ لہذا، بائنری میں نمبر 5.625 کو 101.101 کے طور پر دکھایا گیا ہے اور یہ 1*22 + 0*21 + 1*20 + 1*2-1 + 0*2-2 + 1*2-3 کے برابر ہوگا۔ اور اگر دو کی مثبت طاقتیں ہمیشہ پورے اعشاریہ نمبر (1، 2، 4، 8، 16، وغیرہ) دیتی ہیں، تو پھر منفی کے ساتھ سب کچھ زیادہ پیچیدہ ہوتا ہے (0.5، 0.25، 0.125، 0,0625، وغیرہ)۔ مسئلہ یہ ہے کہ ہر اعشاریہ کو محدود بائنری فریکشن کے طور پر نہیں دکھایا جا سکتا. اس طرح، بائنری فریکشن کی شکل میں ہمارا بدنام زمانہ 0.1 متواتر قدر 0.0(0011) کے طور پر ظاہر ہوتا ہے۔ نتیجتاً، کمپیوٹر میموری میں اس نمبر کی حتمی قدر بٹ گہرائی کے لحاظ سے مختلف ہوگی۔

اب یہ یاد رکھنے کا وقت ہے کہ کمپیوٹر میموری میں حقیقی نمبر کیسے محفوظ ہوتے ہیں۔ عام طور پر، ایک حقیقی نمبر تین اہم حصوں پر مشتمل ہوتا ہے - نشان، مانٹیسا اور ایکسپوننٹ۔ نشان یا تو جمع یا مائنس ہو سکتا ہے، اس لیے اس کے لیے ایک بٹ مختص کیا جاتا ہے۔ لیکن مینٹیسا اور ایکسپوننٹ کے بٹس کی تعداد کا تعین اصلی قسم سے ہوتا ہے۔ لہذا، حقیقی قسم کے لیے، مینٹیسا کی لمبائی 23 بٹس ہے (1 کے برابر ایک بٹ کو مینٹیسا کے آغاز میں واضح طور پر شامل کیا گیا ہے، اور نتیجہ 24 ہے)، اور ایکسپوننٹ 8 بٹس ہے۔ کل 32 بٹس، یا 4 بائٹس ہیں۔ اور ڈبل PRECISION قسم کے لیے، مینٹیسا کی لمبائی 52 بٹس ہوگی، اور ایکسپوننٹ 11 بٹس ہوگا، کل 64 بٹس، یا 8 بائٹس۔ PostgreSQL فلوٹنگ پوائنٹ نمبرز کے لیے زیادہ درستگی کی حمایت نہیں کرتا ہے۔

آئیے اپنے اعشاریہ نمبر 0.1 کو حقیقی اور ڈبل درستگی دونوں اقسام میں پیک کریں۔ چونکہ ایکسپوننٹ کی علامت اور قدر ایک جیسی ہے، اس لیے ہم مانٹیسا پر توجہ مرکوز کریں گے (میں جان بوجھ کر ایکسپوننٹ کی قدروں اور صفر حقیقی قدروں کو ذخیرہ کرنے کی غیر واضح خصوصیات کو چھوڑتا ہوں، کیونکہ وہ سمجھ کو پیچیدہ بناتے ہیں اور جوہر سے توجہ ہٹاتے ہیں۔ مسئلہ کے بارے میں، اگر دلچسپی ہو، تو IEEE 754 معیار دیکھیں)۔ ہمیں کیا ملے گا؟ سب سے اوپر کی لائن میں میں اصلی قسم کے لیے "مانٹیسا" دوں گا (آخری بٹ کو 1 سے قریب ترین نمائندگی کرنے والے نمبر کو مدنظر رکھتے ہوئے، بصورت دیگر یہ 0.099999 ہوگا...)، اور نیچے کی لائن میں - کے لیے ڈبل درستگی کی قسم:

0.000110011001100110011001101
0.00011001100110011001100110011001100110011001100110011001

ظاہر ہے یہ دو بالکل مختلف نمبر ہیں! اس لیے، موازنہ کرتے وقت، پہلا نمبر صفر کے ساتھ پیڈ کیا جائے گا اور اس لیے، دوسرے سے بڑا ہوگا (راؤنڈنگ کو مدنظر رکھتے ہوئے - جس پر بولڈ میں نشان لگایا گیا ہے)۔ یہ ہماری مثالوں سے ابہام کی وضاحت کرتا ہے۔ دوسری مثال میں، واضح طور پر بیان کردہ نمبر 0.1 کو ڈبل PRECISION قسم پر ڈالا جاتا ہے، اور پھر اس کا موازنہ حقیقی قسم کی ایک بڑی تعداد کے ساتھ کیا جاتا ہے۔ دونوں کو ایک ہی قسم میں کم کیا گیا ہے، اور ہمارے پاس بالکل وہی ہے جو ہم اوپر دیکھتے ہیں۔ آئیے استفسار میں ترمیم کریں تاکہ سب کچھ اپنی جگہ پر آجائے:

********* ЗАПРОС *********
SELECT 0.1::REAL > 0.1::DOUBLE PRECISION;
**************************
?column?
----------
t
(1 строка)

اور درحقیقت، نمبر 0.1 کی دوہری کمی کو REAL اور Double PRECISION کرنے سے، ہمیں اس پہیلی کا جواب ملتا ہے:

********* ЗАПРОС *********
SELECT 0.1::REAL::DOUBLE PRECISION;
**************************

      float8       
-------------------
0.100000001490116
(1 строка)

یہ اوپر کی تیسری مثال کی بھی وضاحت کرتا ہے۔ نمبر 123 سادہ ہے۔ مینٹیسا کو 24 بٹس میں فٹ کرنا ناممکن ہے۔ (23 واضح + 1 مضمر)۔ زیادہ سے زیادہ عدد جو 24 بٹس میں فٹ ہو سکتا ہے 224-1 = 16 ہے، لہذا، ہمارے نمبر 777 کو قریب ترین نمائندگی کرنے والے 215 میں تبدیل کر دیا گیا ہے، ہم اب یہ منظرنامہ نہیں دیکھتے ہیں۔

********* ЗАПРОС *********
SELECT 123456789::DOUBLE PRECISION::INT;
**************************
   int4   
-----------
123456789
(1 строка)

بس۔ یہ پتہ چلتا ہے کہ کوئی معجزات نہیں ہیں. لیکن بیان کردہ ہر چیز یہ سوچنے کی ایک اچھی وجہ ہے کہ آپ کو حقیقی قسم کی کتنی ضرورت ہے۔ شاید اس کے استعمال کا سب سے بڑا فائدہ درستگی کے معروف نقصان کے ساتھ حسابات کی رفتار ہے۔ لیکن کیا یہ ایک عالمگیر منظر نامہ ہوگا جو اس قسم کے بار بار استعمال کا جواز پیش کرے گا؟ مت سوچو۔

ماخذ: www.habr.com

نیا تبصرہ شامل کریں