افتح واجهة PHP التفاعلية (php -a) واكتب echo 0.1 + 0.2; — بدلًا من 0.3 ستحصل على 0.3 الذي يبدو صحيحًا عند العرض لكن المقارنة 0.1 + 0.2 == 0.3 تُرجع خطأً داخليًا في لغات كثيرة أخرى مثل JavaScript وPython، لأن القيمة المخزَّنة فعليًا هي 0.30000000000000004. هذا ليس خطأ في لغة برمجة معيّنة، بل نتيجة مباشرة لكيفية تمثيل معيار IEEE 754 للأعداد الكسرية ثنائيًا.
الأجزاء الثلاثة لرقم ذي فاصلة عائمة
يُخزَّن رقم وفق IEEE 754 كثلاثة مكوّنات: إشارة (موجب أو سالب)، ومعامل (الأرقام الدالة للرقم)، وأس (القوة التي تُزاح بها الفاصلة). يشبه هذا الترميز العلمي: 1.5 × 10²، لكن بالنظام الثنائي.
لماذا لا يمكن تمثيل 0.1 بدقة في النظام الثنائي
0.1 في النظام العشري كسر لا نهائي في النظام الثنائي (على غرار كون 1/3 لا نهائيًا في النظام العشري). يخزّن الحاسوب عددًا محدودًا فقط من بتات المعامل، لذا يُقرَّب الرقم إلى أقرب قيمة ممكن تمثيلها — وهذا التقريب هو ما يسبب "الخطأ" الظاهر.
أين يضرّ هذا فعليًا: سلال التسوق والفواتير
صفحة دفع تجمع أسعار العناصر كأرقام عائمة بسيطة قد ينحرف مجموعها سنتًا أو اثنين عن القيمة المتوقعة بعد عدد كافٍ من العناصر — كل عملية جمع تقرّب قليلًا، وتتراكم الأخطاء بدلًا من أن تلغي بعضها. لهذا تعمل أنظمة الدفع عادة بوحدات صحيحة صغيرة (قروش أو سنتات) أو تستخدم نوعًا عشريًا مخصصًا، بدلًا من جمع الأعداد العائمة مباشرة.
لماذا نحتاج هذا
- فهم وتشخيص أخطاء تقريب غير متوقعة في حسابات مالية أو علمية.
- رؤية التمثيل الثنائي الدقيق لرقم عائم معيّن.
- شرح لزميل أو طالب لماذا تُعدّ مقارنة الأعداد الكسرية بالتساوي التام ممارسة سيئة.
الأعداد شبه الطبيعية بالقرب من الصفر
عندما تكون قيمة رقم ما صغيرة جدًا للتمثيل المعتاد (معامل ذو رقم دال يبدأ بواحد ضمني)، ينتقل IEEE 754 إلى الوضع شبه الطبيعي (denormalized)، حيث يُسقَط هذا الواحد الضمني — يتيح هذا تمثيل أعداد أصغر قيمة مطلقة على حساب فقدان دقة تدريجي بدلًا من قفزة مفاجئة إلى الصفر. هذا الانتقال "السلس" نحو الصفر أفضل من التصفير المفاجئ، لكن الحسابات شبه الطبيعية أبطأ ملحوظًا من الحسابات العادية على بعض المعالجات.