مستوى المقال: مبتدئ — مناسب لو لسه في بداية طريقك في البرمجة، ومفيش عندك خلفية عن طريقة تخزين الأرقام في ذاكرة الكمبيوتر. هنبدأ بمثال بسيط، وبعدين نرجع نشرح العلم اللي وراه بدقة.
بعد ما تخلّص المقال ده، هتعرف بالظبط ليه عدّاد بيوصل لـ 2,147,483,647 وفجأة يقلب لرقم سالب، وإزاي تمنع ده يحصل في قاعدة بياناتك أو كودك قبل ما يكسر شغلك.
ليه العدّاد بيرجع رقم سالب فجأة؟
المشكلة باختصار
لو عندك عمود بيعدّ حاجة — مشاهدات، طلبات، نقاط — وفجأة لقيت الرقم بقى بالسالب، أول رد فعل بيكون: "في باج في الكود". غالبًا لأ. ده سلوك متوقّع اسمه تجاوز الأعداد الصحيحة (Integer Overflow). بيحصل لما الرقم يتخطّى أكبر قيمة يقدر النوع يخزّنها، فيلفّ ويرجع من الأول. المشكلة مش في منطقك، دي حدود الذاكرة نفسها.
الحكاية بمثال بسيط: عدّاد السيارة
تخيّل عدّاد الكيلومترات الميكانيكي القديم في عربية. فيه 6 خانات، فبيعدّ من 000000 لحد 999999. لما توصل لآخر رقم وتمشي كيلومتر زيادة، الخانات كلها بتلفّ وترجع 000000. الرقم مرجعش صفر عشان العربية اتصلحت، رجع صفر لأن مفيش مكان لخانة سابعة.
الكمبيوتر بيعمل نفس الحاجة بالظبط. النوع الشائع اسمه int بعرض 32 بت. عنده عدد خانات ثابت، ولمّا يوصل لأكبر رقم ويزيد واحد، بيلفّ. الفرق الوحيد: عدّاد العربية بيرجع صفر، والكمبيوتر بيرجع لأصغر رقم سالب. هنعرف ليه دلوقتي.
طيب علميًا بيحصل إيه؟
النوع int32 بيتخزّن في 32 بت (خانة صفر أو واحد). أول بت من الشمال اسمه بت الإشارة (sign bit): لو صفر، الرقم موجب؛ لو واحد، الرقم سالب. الطريقة دي اسمها المتمّم الثنائي (Two's Complement)، وهي المعيار في كل المعالجات الحديثة.
أكبر رقم موجب بيبقى بت الإشارة صفر وباقي الـ 31 بت واحدات، يعني 2,147,483,647. أول ما تزيد واحد، بتّ الإشارة بيقلب لواحد، والباقي أصفار، فالنتيجة تبقى أصغر رقم: -2,147,483,648. مدى النوع كله من -2,147,483,648 لحد 2,147,483,647. الشريط ده بيوضّح لحظة الالتفاف بالظبط:
في الصورة استخدمنا نوع أصغر (8 بت) عشان يبان بسهولة: مداه من -128 لحد 127. أول ما تزيد على 127 بيرجع -128. نفس المبدأ بالظبط، بس بأرقام أصغر.
جرّبها بنفسك: كود بيوريك الانقلاب
الكود ده بلغة بايثون بيستخدم نوع ثابت العرض (int32) عشان يوريك الالتفاف الحقيقي:
# لازم numpy عشان نوع ثابت العرض: pip install numpy
import numpy as np
x = np.int32(2_147_483_647) # أكبر قيمة في int32
print(x + np.int32(1)) # النتيجة: -2147483648 ← انقلب سالب
# بايثون العادي مبيفيضش، بيكبّر الرقم لوحده:
y = 2_147_483_647
print(y + 1) # النتيجة: 2147483648 ← مفيش انقلاب