JavaRush /جاوا بلاگ /Random-UR /حقیقی اعداد کا آلہ

حقیقی اعداد کا آلہ

گروپ میں شائع ہوا۔
ہیلو! آج کے لیکچر میں ہم جاوا میں نمبرز کے بارے میں اور خاص طور پر حقیقی نمبروں کے بارے میں بات کریں گے۔ حقیقی اعداد کا آلہ - 1گھبرائیں نہیں! :) لیکچر میں ریاضی کی کوئی مشکل نہیں ہوگی۔ ہم حقیقی نمبروں کے بارے میں خصوصی طور پر اپنے "پروگرامر" کے نقطہ نظر سے بات کریں گے۔ تو، "حقیقی اعداد" کیا ہیں؟ حقیقی اعداد وہ اعداد ہوتے ہیں جن کا جزوی حصہ ہوتا ہے (جو صفر ہو سکتا ہے)۔ وہ مثبت یا منفی ہو سکتے ہیں۔ یہاں کچھ مثالیں ہیں: 15 56.22 0.0 1242342343445246 -232336.11 حقیقی نمبر کیسے کام کرتا ہے؟ بالکل آسان: یہ ایک عددی حصہ، ایک جزوی حصہ اور ایک نشان پر مشتمل ہوتا ہے۔ مثبت نمبروں کے لیے نشان عام طور پر واضح طور پر ظاہر نہیں ہوتا ہے، لیکن منفی نمبروں کے لیے یہ اشارہ کیا جاتا ہے۔ اس سے پہلے، ہم نے تفصیل سے جانچ کی تھی کہ جاوا میں نمبروں پر کون سے آپریشن کیے جا سکتے ہیں۔ ان میں بہت سے معیاری ریاضیاتی آپریشنز تھے - جوڑ، گھٹاؤ وغیرہ۔ آپ کے لیے کچھ نئے بھی تھے: مثال کے طور پر، تقسیم کا بقیہ۔ لیکن اعداد کے ساتھ کام کرنا کمپیوٹر کے اندر کیسے کام کرتا ہے؟ وہ کس شکل میں میموری میں محفوظ ہیں؟

اصلی نمبروں کو میموری میں محفوظ کرنا

میرے خیال میں یہ آپ کے لیے کوئی دریافت نہیں ہو گا کہ تعداد بڑی اور چھوٹی ہو سکتی ہے :) ان کا ایک دوسرے سے موازنہ کیا جا سکتا ہے۔ مثال کے طور پر، نمبر 100 نمبر 423324 سے کم ہے۔ کیا یہ کمپیوٹر اور ہمارے پروگرام کے آپریشن کو متاثر کرتا ہے؟ اصل میں - جی ہاں . ہر نمبر کو جاوا میں قدروں کی ایک مخصوص رینج سے ظاہر کیا جاتا ہے :
قسم میموری کا سائز (بٹس) اقدار کی حد
byte 8 بٹ -128 سے 127
short 16 بٹ -32768 سے 32767
char 16 بٹ غیر دستخط شدہ عدد جو UTF-16 حروف کی نمائندگی کرتا ہے (حروف اور اعداد)
int 32 بٹس -2147483648 سے 2147483647 تک
long 64 بٹس -9223372036854775808 سے 9223372036854775807
float 32 بٹس 2 -149 سے (2-2 -23 )*2 127
double 64 بٹس 2 -1074 سے (2-2 -52 )*2 1023
آج ہم آخری دو اقسام کے بارے میں بات کریں گے - floatاور double. دونوں ایک ہی کام انجام دیتے ہیں - جزوی اعداد کی نمائندگی کرتے ہیں۔ انہیں اکثر " فلوٹنگ پوائنٹ نمبرز" بھی کہا جاتا ہے ۔ اس اصطلاح کو مستقبل کے لیے یاد رکھیں :) مثال کے طور پر نمبر 2.3333 یا 134.1212121212۔ کافی عجیب۔ سب کے بعد، یہ پتہ چلتا ہے کہ ان دو اقسام کے درمیان کوئی فرق نہیں ہے، کیونکہ وہ ایک ہی کام انجام دیتے ہیں؟ لیکن ایک فرق ہے۔ اوپر والے جدول میں "میموری میں سائز" کالم پر توجہ دیں۔ تمام نمبرز (اور صرف نمبرز نہیں - عام طور پر تمام معلومات) بٹس کی شکل میں کمپیوٹر میموری میں محفوظ ہیں۔ تھوڑا سا معلومات کی سب سے چھوٹی اکائی ہے۔ یہ بہت آسان ہے۔ کوئی بھی بٹ یا تو 0 یا 1 کے برابر ہوتا ہے۔ اور لفظ " bit " خود انگریزی " binary digit " - ایک بائنری نمبر سے آتا ہے۔ میرے خیال میں آپ نے شاید ریاضی میں بائنری نمبر سسٹم کے وجود کے بارے میں سنا ہوگا۔ کوئی بھی اعشاریہ نمبر جس سے ہم واقف ہیں اسے ایک اور صفر کے سیٹ کے طور پر دکھایا جا سکتا ہے۔ مثال کے طور پر، بائنری میں نمبر 584.32 اس طرح نظر آئے گا: 100100100001010001111 ۔ اس نمبر میں ہر ایک اور صفر ایک الگ بٹ ہے۔ اب آپ کو ڈیٹا کی اقسام کے درمیان فرق کے بارے میں زیادہ واضح ہونا چاہیے۔ مثال کے طور پر، اگر ہم متعدد قسمیں بناتے ہیں float، تو ہمارے پاس صرف 32 بٹس ہوتے ہیں۔ نمبر بناتے وقت، floatکمپیوٹر کی میموری میں اس کے لیے کتنی جگہ مختص کی جائے گی۔ اگر ہم نمبر بنانا چاہتے ہیں 123456789.65656565656565، بائنری میں یہ اس طرح نظر آئے گا: 11101011011110011010001010110101000000 ۔ یہ 38 ون اور زیرو پر مشتمل ہے، یعنی اسے میموری میں محفوظ کرنے کے لیے 38 بٹس کی ضرورت ہے۔ یہ نمبر صرف قسم میں float"فٹ" نہیں ہوگا ! لہذا، نمبر 123456789 کو ایک قسم کے طور پر دکھایا جا سکتا ہے double۔ اسے ذخیرہ کرنے کے لیے زیادہ سے زیادہ 64 بٹس مختص کیے گئے ہیں: یہ ہمارے لیے مناسب ہے! یقینا، اقدار کی حد بھی موزوں ہوگی۔ سہولت کے لیے، آپ ایک عدد کو خلیات کے ساتھ ایک چھوٹے خانے کے طور پر سوچ سکتے ہیں۔ اگر ہر ایک بٹ کو ذخیرہ کرنے کے لیے کافی سیلز موجود ہیں، تو ڈیٹا کی قسم کا انتخاب درست طریقے سے کیا جاتا ہے :) حقیقی اعداد کا آلہ - 2یقیناً، مختص میموری کی مختلف مقداریں بھی خود نمبر کو متاثر کرتی ہیں۔ براہ کرم نوٹ کریں کہ اقسام کی قدروں کی مختلف حدود floatہوتی ہیں ۔ doubleعملی طور پر اس کا کیا مطلب ہے؟ ایک عدد doubleعدد سے زیادہ درستگی کا اظہار کر سکتا ہے float۔ 32 بٹ فلوٹنگ پوائنٹ نمبرز (جاوا میں بالکل اسی قسم کی ہے float) میں تقریباً 24 بٹس کی درستگی ہوتی ہے، یعنی تقریباً 7 اعشاریہ 7 مقامات۔ اور 64 بٹ نمبرز (جاوا میں یہ قسم ہے double) میں تقریباً 53 بٹس کی درستگی ہوتی ہے، یعنی تقریباً 16 اعشاریہ مقامات۔ یہاں ایک مثال ہے جو اس فرق کو اچھی طرح سے ظاہر کرتی ہے:
public class Main {

   public static void main(String[] args)  {

       float f = 0.0f;
       for (int i=1; i <= 7; i++) {
           f += 0.1111111111111111;
       }

       System.out.println(f);
   }
}
اس کے نتیجے میں ہمیں یہاں کیا حاصل کرنا چاہئے؟ ایسا لگتا ہے کہ سب کچھ بہت آسان ہے. ہمارے پاس نمبر 0.0 ہے، اور ہم اس میں 0.1111111111111111 لگاتار 7 بار شامل کرتے ہیں۔ نتیجہ 0.7777777777777777 ہونا چاہیے۔ لیکن ہم نے ایک نمبر بنایا float۔ اس کا سائز 32 بٹس تک محدود ہے اور جیسا کہ ہم نے پہلے کہا، یہ تقریباً 7ویں اعشاریہ تک نمبر دکھانے کی صلاحیت رکھتا ہے۔ لہذا، آخر میں، کنسول میں ہمیں جو نتیجہ ملے گا وہ ہماری توقع سے مختلف ہو گا:

0.7777778
ایسا لگتا تھا کہ نمبر "کاٹ دیا گیا ہے۔" آپ پہلے ہی جانتے ہیں کہ ڈیٹا کو میموری میں کیسے محفوظ کیا جاتا ہے - بٹس کی شکل میں، اس لیے آپ کو حیران نہیں ہونا چاہیے۔ یہ واضح ہے کہ ایسا کیوں ہوا: نتیجہ 0.7777777777777777 صرف ہمارے لیے مختص کردہ 32 بٹس میں فٹ نہیں ہوا، اس لیے اسے ایک قسم کے متغیر میں فٹ کرنے کے لیے چھوٹا کر دیا گیا float:) ہم اپنی مثال میں متغیر کی قسم کو تبدیل کر سکتے ہیں double، اور پھر حتمی نتیجہ کم نہیں کیا جائے گا:
public class Main {

   public static void main(String[] args)  {

       double f = 0.0;
       for (int i=1; i <= 7; i++) {
           f += 0.1111111111111111;
       }

       System.out.println(f);
   }
}

0.7777777777777779
پہلے سے ہی 16 اعشاریہ جگہیں ہیں، نتیجہ 64 بٹس میں "فٹ" ہوتا ہے۔ ویسے، شاید آپ نے محسوس کیا کہ دونوں صورتوں میں نتائج بالکل درست نہیں تھے؟ حساب کتاب معمولی غلطیوں کے ساتھ کیا گیا تھا۔ ہم ذیل میں اس کی وجوہات کے بارے میں بات کریں گے :) اب آئیے چند الفاظ بتاتے ہیں کہ آپ نمبروں کا ایک دوسرے سے موازنہ کیسے کر سکتے ہیں۔

حقیقی نمبروں کا موازنہ

ہم نے جزوی طور پر پہلے ہی آخری لیکچر میں اس مسئلے کو چھوا ہے، جب ہم نے موازنہ کی کارروائیوں کے بارے میں بات کی تھی۔ ہم آپریشنز کا دوبارہ تجزیہ نہیں کریں گے جیسے کہ >, <. آئیے اس کے بجائے ایک اور دلچسپ مثال دیکھیں: >=<=
public class Main {

   public static void main(String[] args)  {

       double f = 0.0;
       for (int i=1; i <= 10; i++) {
           f += 0.1;
       }

       System.out.println(f);
   }
}
آپ کے خیال میں اسکرین پر کون سا نمبر ظاہر ہوگا؟ منطقی جواب یہ ہوگا: نمبر 1۔ ہم نمبر 0.0 سے گننا شروع کرتے ہیں اور لگاتار دس بار اس میں 0.1 کا اضافہ کرتے ہیں۔ سب کچھ درست لگتا ہے، ایک ہونا چاہیے۔ اس کوڈ کو چلانے کی کوشش کریں، اور جواب آپ کو بہت حیران کر دے گا :) کنسول آؤٹ پٹ:

0.9999999999999999
لیکن اتنی سادہ سی مثال میں غلطی کیوں ہوئی؟ O_o یہاں پانچویں جماعت کا طالب علم بھی آسانی سے صحیح جواب دے سکتا تھا، لیکن جاوا پروگرام نے ایک غلط نتیجہ نکالا۔ "غلط" یہاں "غلط" سے بہتر لفظ ہے۔ ہمیں اب بھی ایک نمبر ایک کے بہت قریب ہے، اور نہ صرف کچھ بے ترتیب قدر :) یہ صحیح سے ایک ملی میٹر کے لحاظ سے مختلف ہے۔ لیکن کیوں؟ شاید یہ صرف ایک بار کی غلطی ہے۔ شاید کمپیوٹر کریش ہو گیا؟ آئیے ایک اور مثال لکھنے کی کوشش کرتے ہیں۔
public class Main {

   public static void main(String[] args)  {

       //add 0.1 to zero eleven times in a row
       double f1 = 0.0;
       for (int i = 1; i <= 11; i++) {
           f1 += .1;
       }

       // Multiply 0.1 by 11
       double f2 = 0.1 * 11;

       //should be the same - 1.1 in both cases
       System.out.println("f1 = " + f1);
       System.out.println("f2 = " + f2);

       // Let's check!
       if (f1 == f2)
           System.out.println("f1 and f2 are equal!");
       else
           System.out.println("f1 and f2 are not equal!");
   }
}
کنسول آؤٹ پٹ:

f1 = 1.0999999999999999
f2 = 1.1
f1 и f2 не равны!
تو، یہ واضح طور پر کمپیوٹر کی خرابیوں کا معاملہ نہیں ہے :) کیا ہو رہا ہے؟ اس طرح کی خرابیاں کمپیوٹر کی میموری میں بائنری شکل میں نمبروں کی نمائندگی کرنے کے طریقے سے متعلق ہیں۔ حقیقت یہ ہے کہ بائنری نظام میں نمبر 0.1 کو درست طریقے سے بیان کرنا ناممکن ہے ۔ ویسے، اعشاریہ نظام میں بھی کچھ ایسا ہی مسئلہ ہے: کسر کو درست طریقے سے پیش کرنا ناممکن ہے (اور ⅓ کی بجائے ہمیں 0.3333333333333... ملتا ہے، جو کہ بالکل درست نتیجہ نہیں ہے)۔ یہ ایک چھوٹی سی بات لگتی ہے: اس طرح کے حساب سے، فرق ایک لاکھ حصہ (0.00001) یا اس سے بھی کم ہو سکتا ہے۔ لیکن کیا ہوگا اگر آپ کے انتہائی سنجیدہ پروگرام کا پورا نتیجہ اس موازنہ پر منحصر ہے؟
if (f1 == f2)
   System.out.println("Rocket flies into space");
else
   System.out.println("The launch is canceled, everyone goes home");
ہمیں واضح طور پر دونوں نمبروں کے برابر ہونے کی توقع تھی، لیکن اندرونی میموری ڈیزائن کی وجہ سے، ہم نے راکٹ لانچ کو منسوخ کر دیا۔ حقیقی اعداد کا آلہ - 3اگر ایسا ہے تو، ہمیں یہ فیصلہ کرنے کی ضرورت ہے کہ دو فلوٹنگ پوائنٹ نمبروں کا موازنہ کیسے کیا جائے تاکہ موازنہ کا نتیجہ زیادہ... ummm... پیشین گوئی کے قابل ہو۔ لہذا، ہم نے پہلے ہی قاعدہ نمبر 1 سیکھ لیا ہے جب حقیقی نمبروں کا موازنہ کریں: حقیقی نمبروں کا موازنہ کرتے وقت کبھی بھی فلوٹنگ پوائنٹ نمبرز کا استعمال نہ کریں ۔ == ٹھیک ہے، مجھے لگتا ہے کہ یہ کافی بری مثالیں ہیں :) آئیے ایک اچھی مثال دیکھیں!
public class Main {

   public static void main(String[] args)  {

       final double threshold = 0.0001;

       //add 0.1 to zero eleven times in a row
       double f1 = .0;
       for (int i = 1; i <= 11; i++) {
           f1 += .1;
       }

       // Multiply 0.1 by 11
       double f2 = .1 * 11;

       System.out.println("f1 = " + f1);
       System.out.println("f2 = " + f2);

       if (Math.abs(f1 - f2) < threshold)
           System.out.println("f1 and f2 are equal");
       else
           System.out.println("f1 and f2 are not equal");
   }
}
یہاں ہم بنیادی طور پر وہی کام کر رہے ہیں، لیکن نمبروں کا موازنہ کرنے کے طریقے کو تبدیل کر رہے ہیں۔ ہمارے پاس ایک خاص "درجہ" نمبر ہے - 0.0001، ایک دس ہزارواں۔ یہ مختلف ہوسکتا ہے۔ یہ اس بات پر منحصر ہے کہ کسی خاص معاملے میں آپ کو کس قدر درست موازنہ کی ضرورت ہے۔ آپ اسے بڑا یا چھوٹا بنا سکتے ہیں۔ طریقہ استعمال کرتے ہوئے، Math.abs()ہم ایک عدد کا ماڈیولس حاصل کرتے ہیں۔ ماڈیولس کسی بھی نشان سے قطع نظر نمبر کی قدر ہے۔ مثال کے طور پر، نمبر -5 اور 5 میں ایک ہی ماڈیولس ہوں گے اور وہ 5 کے برابر ہوں گے۔ ہم دوسرے نمبر کو پہلے سے گھٹاتے ہیں، اور اگر نتیجہ کا نتیجہ، نشانی سے قطع نظر، اس حد سے کم ہے جو ہم مقرر کرتے ہیں، تو ہماری تعداد برابر ہے۔ کسی بھی صورت میں، وہ درستگی کی اس ڈگری کے برابر ہیں جو ہم نے اپنے "تھریش ہولڈ نمبر" کا استعمال کرتے ہوئے قائم کی ہے ، یعنی کم از کم وہ ایک دس ہزارویں کے برابر ہیں۔ موازنہ کا یہ طریقہ آپ کو اس غیر متوقع رویے سے بچائے گا جو ہم نے کے معاملے میں دیکھا تھا ==۔ حقیقی نمبروں کا موازنہ کرنے کا ایک اور اچھا طریقہ ایک خاص کلاس استعمال کرنا ہے BigDecimal۔ یہ کلاس خاص طور پر ایک جزوی حصے کے ساتھ بہت بڑی تعداد کو ذخیرہ کرنے کے لیے بنائی گئی تھی۔ اس کے برعکس doubleاور float، جب BigDecimalاضافہ، گھٹاؤ اور دیگر ریاضیاتی عمل آپریٹرز ( +-، وغیرہ) کا استعمال کرتے ہوئے نہیں بلکہ طریقوں کا استعمال کرتے ہوئے انجام دیے جاتے ہیں۔ ہمارے معاملے میں یہ ایسا ہی نظر آئے گا:
import java.math.BigDecimal;

public class Main {

   public static void main(String[] args)  {

       /*Create two BigDecimal objects - zero and 0.1.
       We do the same thing as before - add 0.1 to zero 11 times in a row
       In the BigDecimal class, addition is done using the add () method */
       BigDecimal f1 = new BigDecimal(0.0);
       BigDecimal pointOne = new BigDecimal(0.1);
       for (int i = 1; i <= 11; i++) {
           f1 = f1.add(pointOne);
       }

       /*Nothing has changed here either: create two BigDecimal objects
       and multiply 0.1 by 11
       In the BigDecimal class, multiplication is done using the multiply() method*/
       BigDecimal f2 = new BigDecimal(0.1);
       BigDecimal eleven = new BigDecimal(11);
       f2 = f2.multiply(eleven);

       System.out.println("f1 = " + f1);
       System.out.println("f2 = " + f2);

       /*Another feature of BigDecimal is that number objects need to be compared with each other
       using the special compareTo() method*/
       if (f1.compareTo(f2) == 0)
           System.out.println("f1 and f2 are equal");
       else
           System.out.println("f1 and f2 are not equal");
   }
}
ہمیں کس قسم کا کنسول آؤٹ پٹ ملے گا؟

f1 = 1.1000000000000000610622663543836097232997417449951171875
f2 = 1.1000000000000000610622663543836097232997417449951171875
f1 и f2 равны
ہمیں بالکل وہی نتیجہ ملا جس کی ہم توقع کرتے تھے۔ اور اس بات پر توجہ دیں کہ ہمارے اعداد کتنے درست نکلے، اور کتنے اعشاریہ ان میں فٹ ہوتے ہیں! floatمیں اور اس سے بھی زیادہ double! BigDecimalمستقبل کے لیے کلاس کو یاد رکھیں ، آپ کو اس کی ضرورت ضرور پڑے گی :) افف! لیکچر کافی لمبا تھا، لیکن آپ نے یہ کیا: شاباش! :) اگلے سبق میں ملیں گے، مستقبل کے پروگرامر!
تبصرے
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION