المستوى: مبتدئ — المقال ده مكتوب لأي حد لسه في بداية طريقه في البرمجة، شاف نتيجة حسابية غريبة على الشاشة وعايز يفهم بيحصل إيه بالظبط، من غير رياضيات معقّدة.
ليه 0.1 + 0.2 مش بيساوي 0.3 في كل لغات البرمجة؟
لو كتبت 0.1 + 0.2 في أي لغة برمجة تقريبًا ولقيت الناتج 0.30000000000000004 بدل 0.3، فالكمبيوتر مش بايظ وانت مش غلطان. في آخر المقال ده هتعرف بالظبط ليه ده بيحصل، إمتى يبقى خطر حقيقي على شغلك، وإزاي تقفله في سطر أو سطرين.
المشكلة باختصار
افتح console المتصفح دلوقتي واكتب 0.1 + 0.2. الناتج هيكون 0.30000000000000004. وجرّب 0.1 + 0.2 === 0.3 هيرجّعلك false. ده مش bug في JavaScript ولا في Python ولا في Java. ده سلوك مكتوب في معيار رسمي اسمه IEEE 754، وكل المعالجات الحديثة بتنفّذه بنفس الطريقة بالظبط. السبب باختصار: الكمبيوتر بيخزّن الأرقام العشرية بنظام مالوش القدرة إنه يكتب 0.1 بدقة كاملة، فبيقرّبها، والتقريب الصغير ده بيطفو على السطح أول ما تجمع رقمين.
الأول، خلّينا نفهمها من غير كمبيوتر خالص
تعالى نلعب لعبة بسيطة بالورقة والقلم. قسّم 1 على 3. هيطلعلك 0.3333... والتلاتات مش بتخلص أبدًا. لو قلتلك "اكتبلي ناتج 1÷3 في أربع خانات بس بعد العلامة العشرية"، هتكتب 0.3333، وبكده تكون قرّبت الرقم وخسرت جزء صغير منه.
دلوقتي اضرب اللي كتبته في 3: 0.3333 × 3 = 0.9999. المفروض يطلع 1 بالظبط، بس طلع 0.9999. الفرق الصغير ده — 0.0001 — هو تمن إنك حاولت تكتب رقم تمثيله لا نهائي في مساحة محدودة.
الكمبيوتر بيقع في نفس الفخ بالظبط، بفرق واحد: هو مش بيحسب بنظام العشرة اللي احنا متعودين عليه، هو بيحسب بنظام الاتنين. وفي نظام الاتنين، الرقم اللي "تلاتاته مش بتخلص" مش هو 1÷3 — لأ، هو 0.1 نفسه.
طب ليه 0.1 بالذات بتعمل مشكلة في نظام الاتنين؟
في النظام العشري، الخانات بعد العلامة معناها أعشار، ثم أجزاء من مئة، ثم من ألف. في النظام الثنائي (نظام الاتنين)، الخانات بعد العلامة معناها نُص (1/2)، ثم رُبع (1/4)، ثم تُمن (1/8)، وهكذا. يعني الكمبيوتر يقدر يكتب بدقة كاملة أي رقم تقدر تركّبه من جمع كسور مقامها قوة للاتنين، وبس.
0.5سهل: هو نُص بالظبط، بيتكتب0.1في الثنائي.0.25سهل: هو رُبع، بيتكتب0.01.0.75سهل: نُص زائد رُبع، بيتكتب0.11.
لكن جرّب تركّب 0.1 العشري من جمع نُص ورُبع وتُمن وما بعدهم... مش هتقدر توصّلها بالظبط مهما ضفت خانات. التمثيل الثنائي للكسر 0.1 هو 0.0001100110011001100110011... والنمط 0011 بيفضل بيتكرر للأبد، زي التلاتات بالظبط في 1÷3. الصورة اللي في أول المقال دي بالضبط: كل مربّع بيمثّل خانة ثنائية واحدة في تمثيل 0.1، والنمط ماشي ومش بيقف.