إستخدام double و float: كيف يؤدي إلى خسارة حتمية أو أرباح زائفة

إستخدام double و float: كيف يؤدي إلى خسارة حتمية أو أرباح زائفة


عندما يتعلق الأمر بالتعامل مع بعض الكائنات المحتوية على كسور نلجأ عادة إلى إستخدام المتغيرات التي تدعم الكسور العشرية في لغة الجافا.
المتغيرات الكسرية كما تعلم هي double و float.
برغم أن هذا الخيار يبدو منطقياً جداً، إلا أن استخدام float و double في شفراتك المصدرية يؤدي حتماً إلى فقدان نسبة من الدقة في نتيجة الحسابات عند ظروف معينة تحدُث كثيراً.
سأتطرّقُ إلى هذه الظروف و كيف تستطيع تفاديها.

كيف يتم تعريف float و double

نُعرف المتغير من النوع double و float بالطريقة التالية
1
2
    double first = 7.9;
    float second = 4.9f;
هذا يعني أن المعتغير first يحوي القيمة 7.9 و المتغير second يحوي القيمة 4.9.

عندما تختلف النتيجة بين الآلة الحاسبة و برنامجك

نوعا البيانات float و double يستطيعان إستيعاب الأرقام الصحيحة و الأرقام الكسرية أيضاً، لذا يكثُر إستخدامهما عند الحاجة إلى التعامل مع الكسور.
عادة ما يكون التعامل مع الكسور بسبب الحوجة إلى دقّة أعلى، و الدقة الأعلى تعني أن النظام ربما يكون ذا أهمية عالية.
كما تعلم فإن الحاسب يتعامل بلغة 0، 1، فالمتغيرات التي تُعرف كمتغيرات كسرية float أو double تُخزن في الحاسب كأرقام ثنائية.
وهنا تترعرع المُشكلة.
توجد بعض الكسور التي تكون نتيجة تحويلها من عدد عشري إلى عدد ثنائي عدداً ثنائياً لا نهائي.
مثالُ ذلك، عملية تحويل العدد العشري 0.1.
هذه هي عمليةُ التحويل
1
2
3
4
5
6
0.1 * 2 = 0.2      // 0
0.2 * 2 = 0.4     // 0
0.4 * 2 = 0.8   // 0
0.8 * 2 = 1.6   // 1
0.6 * 2 = 1.2   // 1
0.2 * 2 = 0.4   // 0 --> تكرار
عندما يكون ناتج عملية التحويل عدداً لا نهائياً تقل الدقة في التعامل مع العمليات الرياضية.
مثلاً عند إجراء العملية 6 * 0.3
الدقة في double و float
إعلم أن الرقم 0.3 ناتجه الثنائي لا نهائي، و بالتالي عند تنفيذ الشفرة المصدرية التالية
1
2
3
4
        double a = 6.00;
        double b = 0.3;
       
        System.out.println("The Result = " + a * b);
تكون هذه هي النتيجة !!!
ناتج تنفيذ ضرب عددين كسريين في الجافا

هذا الفرق قد يضعُ حياة البشر على المحك

هذا الإختلاف في النتيجة بسبب إستخدام double أو float يؤدي إلى مشكلة بسيطة في شكلها و لها تأثيرات مختلفة على مستويات عدة منها الحرج والذي يؤدي إلى نتائج مأساوية و منها البسيط الذي يتعلق بالشكل فقط.
من التأثيرات المُحتملة لهذا الفرق إذا لم يُعالج:
  1. ظهور الأرقام ككسور طويلة في الشاشة حين لم يتوقع المبرمج أن يحدث ذلك.
  2. في الأنظمة الحسابية يحدث إختلاف طفيف يكلف المُنشأة الكثير من الوقت و المال في محاولة إيجاد سبب الفرق.
  3. في الأنظمة الطبية يؤدي إلى حصول المريض على جُرعة زائدة أو ناقصة.
  4. في الأنظمة العسكرية يؤدي إلى سقوط صواريخ في غير ما خُطط له.
  5. في أنظمة الفضاء يؤدي إلى إنحراف مكوك فضائي عن مساره!

كيف تتغلب على هذه المشكلة

للحصول على الدقة المطلوبة و لتلافي هذه المشكلة بإمكانك إستخدام الفئة BigDecimal.
الفئة BigDecimal تحتوي على دوال لإجراء العمليات الرياضية مثل multiply و remainder و plus.
فإذا استخدمتها في المثال السابق كما يلي
1
2
3
4
       BigDecimal c = new BigDecimal("6.00");
       BigDecimal d = new BigDecimal("0.3");       
       
       System.out.println("The Precise Result = " + c.multiply(d));
فستجد أن النتيجة أصبحت دقيقة تماماً
إستخدام BigDecimal مع الكسور
نعم، تأثيرٌ صغير و كسورٌ من ألف، و لكنّ طبيعة العمل هي التي تتحكم في مقدار الدقة الواجب الذي يجب تطبيقه بالنظام.
طبيعةُ العمل تعني مجال استخدام البرنامج، و نادراً ما تخلو النُظم و البرامج من عمليات حسابية، و لكن إهتمام أصحاب العمل و تأثيرُ هذه الدقة على الحياة و المجتمع هي الفيصل.
شكرا لك ولمرورك