تقنية

تخزين float32: هل تبقى زيادة الواحد عند كل مقدار؟

العدد 16777217 في منتصف موضعين متاحين في تمثيل binary32
رسم تمثيل عددي مؤلف؛ لا تجربة جهاز أو تشغيل مكتبة.

دقة float32 وزيادة الواحد سؤال عن القيم التي يستطيع التمثيل الاحتفاظ بها، وليس عن صحة الجمع الرياضي. نختار عددا كبيرا ونقارن جيرانه في تمثيلين ثنائيين. بهذه المقارنة نفصل الرقم المقصود عن الرقم الذي يمكن أن يخزن في حقل عددي يستخدم مع بيانات النموذج.

الخلاصة السريعة

لا؛ عند 16777216 في binary32 تفصل وحدتان بين هذا العدد وجاره الأكبر، فتضيع زيادة الواحد تحت التقريب للأقرب مع تفضيل الزوجي.

  • يوضح دليل IEEE دقة 24 بتا للأرقام العادية في التمثيل الأحادي و 53 في المزدوج. نختار صراحة التقريب للأقرب مع تفضيل الزوجي عند التعادل. [1]
  • في مثالنا 16777216 يساوي 2 أس 24. الجار الأكبر في binary32 هو 16777218 ؛ العدد 16777217 يقع في منتصفهما، فيرجع إلى 16777216 وفق تفضيل الزوجي في الرقم الدال.
  • في binary64 يمكن تمثيل الأعداد الثلاثة هنا بالضبط. زيادة الواحد ليست أصغر من المسافة المحلية في هذا المثال، لكن ذلك لا يثبت دقة مطلقة عند كل مقدار.
  • التحويل إلى تمثيل أوسع بعد فقد الفرق لا يستعيد القيمة المقصودة. حدد نوع التخزين ومقدار الأعداد وقاعدة التقريب؛ لم نجرب جهازا أو مكتبة أو أداء نموذج.

ما الفرض الذي نثبته قبل المقارنة؟

يشرح دليل Oracle تمثيلي IEEE الأحادي والمزدوج بدقة 24 و 53 بتا للقيمة، ويعرض التقريب إلى أقرب قيمة مع تفضيل الزوجي عند تساوي المسافتين. [1]

نقصد هنا binary32 وbinary64 وفق هذين التمثيلين، ونختار قاعدة الأقرب مع تفضيل الزوجي. هذه قاعدة معلنة للمثال؛ لا ندعي أننا قرأنا إعدادات جهاز المستخدم أو أن كل مسار حساب يستعمل النوع الذي يظهر في اسم ملف.

الفرق المقصود هو واحد صحيح. لا نتحدث عن خطأ قياس طول أو عن ترتيب جمع قائمة؛ نراجع فقط هل يوجد موضع تمثيل يحتفظ بالعدد الناتج قرب مقدار محدد.

أين يقع الواحد بين الجارين؟

نختار 16777216 ، وهو 2 أس 24. من دقة 24 بتا نستنتج أن خطوة binary32 في النطاق الذي يبدأ هنا تساوي 2 أس(24−23)، أي 2. الجاران اللذان يحيطان بنتيجة الزيادة هما 16777216 و 16777218.

الجمع الرياضي 16777216+1 يعطي 16777217. لكنه ليس واحدا من مواضع هذا التمثيل في النطاق المحدد، ويبعد واحدا عن كل جار. وفق تفضيل الزوجي في الرقم الدال، يقع الاختيار على الجار السفلي 16777216 ؛ ليس المقصود مجرد كون الكتابة العشرية للجارين زوجية.

هذه قراءة حسابية من التمثيل المعلن، وليست مخرجات تجربة float32. الزيادة الرياضية صحيحة، لكن الرقم المخزن لا يحمل فرق الواحد. أما زيادة اثنين هنا فتعطي 16777218 ، وهو الجار الممثل التالي.

ماذا يتغير مع binary64 في هذا المثال؟

بدقة 53 بتا تكفي المواضع للاحتفاظ بالأعداد 16777216 و 16777217 و 16777218 بالضبط. لذلك لا تواجه زيادة الواحد هنا الفجوة التي واجهتها في binary32. نستنتج هذا من عرض الدقة، لا من تجربة جمع في مكتبة.

ولا نعمم ذلك على كل عدد كبير أو كسر عشري. المقارنة تتعلق بهذه الأعداد الصحيحة وهذا النطاق؛ اختلاف الدقة يغير شبكة القيم المتاحة، ولا يجعل التمثيل الثنائي اسما آخر للحساب الحقيقي دون حدود.

العدد المقصودbinary32 تحت قاعدتناbinary64 هنا
167772161677721616777216
167772171677721616777217
167772181677721816777218

هل يكفي توسيع النوع بعد التخزين؟

إذا حفظنا الزيادة بالفعل على هيئة 16777216 ، ثم نقلنا هذه القيمة إلى تمثيل أوسع، فقد نقلنا الرقم المحفوظ نفسه. لا يحمل الملف دليلا يميز هل كان الأصل 16777216 أم 16777217 ثم قربناه. توسيع الخانة وحده لا يعيد معلومة فقدت.

نقترح كتابة النوع الفعلي ونطاق القيم المتوقع والفرق الذي يجب حفظه، مع اختبار مناسب للمهمة عند التنفيذ. لم نفحص مكتبة أو جهازا ولم ندرب نموذجا؛ المثال يوضح أين نحتاج مراجعة التمثيل قبل أن نعامل تساوي رقمين مخزنين كدليل على تساوي المقصود.

المصادر ومتابعة القراءة

  1. Oracle Numerical Computation Guide: IEEE arithmetic (يفتح في نافذة جديدة)docs.oracle.com

أُعدّ هذا المقال بصياغة عربية أصلية بالاستناد إلى المصادر أعلاه، وهو مدخل تمهيدي إلى الموضوع. اقرأ منهجية المحتوى وحدوده.