المستوى: مبتدئ. هذا المقال موجّه لمن بدأ البرمجة حديثًا، ولا يفترض أي معرفة سابقة بطريقة تخزين الأرقام داخل الكمبيوتر. هتفهم بعده ليه رقم ممكن "يلف" ويبقى سالب فجأة، وإزاي تتجنّب ده.
ليه عدّاد مشاهدات يوتيوب وقف عند 2 مليار وانقلب سالب؟
في ديسمبر 2014 وصل فيديو "Gangnam Style" إلى 2,147,483,647 مشاهدة، وفجأة العدّاد اتلخبط. السبب مش سيرفرات يوتيوب، ولا اختراق. السبب نوع الرقم اللي كانوا بيعدّوا بيه. لو فهمت السطر الجاي، هتعرف ليه أي عدّاد في أي لغة ممكن يقع نفس الوقعة.
المشكلة باختصار
الكمبيوتر مش بيخزّن الرقم في مساحة لا نهائية. بيحجزله صندوق بحجم ثابت. الصندوق الشائع اسمه 32-bit signed integer، وبيسع أرقام من -2,147,483,648 لحد 2,147,483,647 وبس. لو وصلت للحد الأقصى وزوّدت واحد، الرقم مبيكبرش، لأ ده بيلف ويرجع لأصغر رقم سالب. ده اللي اسمه Integer Overflow.
اتخيلها زي عدّاد الكيلومترات في العربية
تخيّل عدّاد قديم في عربية بـ 6 خانات. أقصى رقم ممكن يوصله هو 999999. لو مشيت كيلومتر واحد كمان، الخانات بتقلب كلها لـ 000000 وتبدأ من الأول. مفيش خانة سابعة تستوعب الزيادة.
الـ integer زي العدّاد ده بالظبط، بفرق واحد: عشان بيخزّن أرقام سالبة كمان، أول ما يعدّي أكبر رقم موجب بيلف ناحية أكبر رقم سالب، مش ناحية الصفر. عشان كده 2,147,483,647 زائد واحد بيدّيك -2,147,483,648.
الشرح العلمي: ليه 32 بت بالظبط؟
الـ "بِت" (bit) خانة بتحمل 0 أو 1. صندوق فيه 32 بت بيقدر يمثّل 2^32 أي 4,294,967,296 احتمال مختلف. لكن لو عايزين نخزّن سالب وموجب، بنخصّص أول بت كـ إشارة (sign bit): 0 معناها موجب، و1 معناها سالب. الطريقة دي اسمها Two's Complement، وهي المعيار في كل المعالجات الحديثة.
النتيجة: نص المدى للموجب (لحد 2,147,483,647) ونص للسالب (لحد -2,147,483,648). لمّا تزوّد واحد على أكبر موجب، البتّات بتتحوّل من 0111...1 إلى 1000...0، وبما إن أول بت بقى 1، الكمبيوتر بيقراها على إنها أصغر رقم سالب. ده مش غلط في الكود، ده سلوك الـ hardware نفسه.
جرّبها بنفسك بالكود
الكود ده بلغة Go بيوريك الانفجار بأرقام حقيقية:
package main
import "fmt"
func main() {
var x int32 = 2147483647 // أكبر قيمة ممكنة في int32
fmt.Println(x) // 2147483647
x = x + 1 // زوّدنا واحد بس
fmt.Println(x) // -2147483648 ← لفّ وبقى سالب
}
في JavaScript الأرقام العادية بتطلع صح لأنها أصلًا 64-bit، لكن أول ما تفرض حساب 32 بت (بـ | 0) بترجع نفس المشكلة:
console.log(2147483647 + 1); // 2147483648 — عادي
console.log((2147483647 + 1) | 0); // -2147483648 — لفّ زي int32
أما Python فمفيهاش overflow في الأعداد الصحيحة أصلًا، لأنها بتكبّر حجم الرقم تلقائيًا حسب الحاجة:
x = 2147483647
print(x + 1) # 2147483648 — بايثون بتوسّع الرقم لوحدهامش حادثة يتيمة: أمثلة من الواقع
- يوتيوب 2014: عدّاد Gangnam Style لمس حد الـ 32 بت، فيوتيوب رقّى العدّاد لـ 64 بت اللي بيوصل لـ 9,223,372,036,854,775,807 (حوالي 9.2 كوينتيليون). جوجل قالت إن مهندسيها شافوا اللحظة دي جاية من شهور وجهّزوا لها.
- طيارة Boeing 787: عدّاد داخلي كان بيعمل overflow بعد 248 يوم تشغيل متواصل، فأصدرت FAA تحذير بإعادة تشغيل دورية لحد ما اتظبط.
- مشكلة سنة 2038: أنظمة كتير بتخزّن الوقت كعدد ثواني في int32 من 1970. الصندوق ده هيمتلي يوم 19 يناير 2038، وبعدها هيلف لرقم سالب لو متعالجش.
الـ trade-off: ليه منستخدمش 64 بت في كل حاجة؟
الحل المباشر هو نوع أكبر زي int64. بتكسب مدى ضخم يكفي لأي عدّاد واقعي. بتخسر ضعف الذاكرة: 8 بايت بدل 4 لكل رقم. على عمود في جدول فيه مليار صف، ده فرق حوالي 4 جيجابايت تخزين، وضغط أعلى على الـ cache والـ network. الافتراض هنا إنك بتعدّ حاجة ممكن تكبر فعلًا (مشاهدات، معرّفات، أرصدة)؛ ساعتها الـ int64 يستاهل تكلفته.
متى لا تقلق من ده أصلًا
مش كل كود محتاج تشيل همّه. متشغلش بالك لو:
- بتكتب بـ Python، لأن أعدادها الصحيحة بتكبر تلقائيًا (التكلفة بطء بسيط مع الأرقام العملاقة).
- أرقامك صغيرة ومحدودة بطبعها زي الأعمار أو عدد عناصر في قائمة قصيرة.
- بتشتغل بأرقام JavaScript عادية وأنت تحت
Number.MAX_SAFE_INTEGERأي 9,007,199,254,740,991.
الخطوة التالية
دوّر في كودك على أي حقل بيعدّ لأعلى بلا سقف معروف: مشاهدات، معرّفات تسلسلية (auto-increment IDs)، أرصدة، عدّادات أحداث. لو لقيت حقل من دول نوعه int32 أو INT في قاعدة البيانات، حوّله لـ int64 أو BIGINT من دلوقتي قبل ما يمتلي وانت في الإنتاج. التغيير وانت فاضي أرخص بكتير من إصلاحه بعد ما العدّاد يلف.
المصادر
- Guinness World Records — First YouTube video to require a 64-bit counter
- Exploring Binary — Gangnam Style Video Overflows YouTube Counter
- Wikipedia — Integer overflow
- Wikipedia — Two's complement
- Go Language Specification — Numeric types
- Python docs — Numeric Types (int)
- MDN — Number.MAX_SAFE_INTEGER
- Wikipedia — Year 2038 problem