الأعداد العشرية في PHP

من موسوعة حسوب
< PHP

الأعداد العشرية (تعرف أيضا بالأعداد الحقيقة real number أو doubles أو float) ويمكن تعريفها باستخدام إحدى الصيغ التالية:

<?php
$a = 1.234; 
$b = 1.2e3; 
$c = 7E-10;
?>

بشكل رسمي:

LNUM          [0-9]+
DNUM          ([0-9]*[\.]{LNUM}) | ({LNUM}[\.][0-9]*)
EXPONENT_DNUM [+-]?(({LNUM} | {DNUM}) [eE][+-]? {LNUM})

حجم الأعداد الكسرية يختلف حسب المنصة، رغم أن الحد الأقصى هو ‎~1.8e308 مع دقةٍ تقارب 14 رقم بعد الفاصلة (تنسيق 64 بت في IEEE).

تقريب الأعداد الكسرية

تمتلك الأعداد الكسرية دقةً محدودةً (تختلف حسب النظام)، وتستخدم PHP عمومًا صيغة IEEE 754 double precision، والتي تعطي خطأً نسبيًا عند التقريب بحدود 1.11e-16، وقد تعطي العمليات الحسابية غير الأساسية أخطاءً أكبر، وبطبيعة الحال، ستتضاعف الأخطاء عند القيام بعدة عمليات معًا. 

إضافةً إلى ذلك، إن الأرقام الحقيقة التي يمكن تمثيلها كأعداد عشرية في نظام العد العشري (الأساس 10)، مثل 0.1 أو 0.7، لا تمتلك تمثيلًا دقيقًا كأعداد عشرية في نظام العد الثنائي، والذي يُستخدم داخليًا بغض النظر عن حجم الجزء العشري؛ وبالتالي لا يمكن تحويلها إلى أعداد في النظام الثنائي دون خسارة جزء صغير من الدقة وقد يؤدي هذا إلى نتائج مربكة، على سبيل المثال، floor((0.1+0.7)*10)‎ سيرجع في العادة القيمة 7 بدلا من العدد المتوقع 8، لأن التمثيل الداخلي سيكون مشابهًا للقيمة 7.9999999999999991118…. 

لذلك لا تثق أبدًا بنتائج الأعداد العشرية إلى آخر رقم في التمثيل، ولا تقارن بين هذه الأعداد مباشرة، استخدم دوال arbitrary precision math و دوال gmp بدلًا من ذلك.

للحصول على تفسير بسيط عن هذا السلوك، يمكنك الاطلاع على floating point guide.

التحويل إلى أعداد عشرية

يمكنك الإطلاع على قسم «تحويل السلاسل النصية إلى أعداد» للمزيد من المعلومات حول التحويل من السلاسل النصية إلى الأعداد العشرية، وبالنسبة لقيم الأنواع الأخرى فيجب تحويلها أولًا إلى أعداد صحيحة ومن ثم إلى أعداد عشرية؛ يمكنك الإطلاع على قسم «التحويل إلى عدد صحيح» للمزيد من المعلومات.

لاحظ أنَّه بدءًا من PHP 5 سيُرمى تنبيهٌ (notice) إذا جرى تحويل كائن object إلى عددٍ عشري.

مقارنة الأعداد العشرية

كما حذّرنا أعلاه، قد يسبب اختبار مساواة قيم الأعداد العشرية مشكلةً، نظرًا للطريقة التي يُمثَّل فيها هذا النوع من الأعداد داخليًا، ومع ذلك، توجد طرائق لإجراء المقارنات دون مشاكل.

لاختبار مساواة قيم الأعداد العشرية، فيجب استخدام حد أعلى للخطأ النسبي بسبب التقريب، هذه القيمة تسمى «إبسلون» (epsilon)، وهي أصغر فرق مقبول في العمليات الحسابية. 

لاحظ أنَّ المتغيرين ‎$a و ‎$b متساويان بدقة 5 أرقام في المثال الآتي:

<?php
$a = 1.23456789;
$b = 1.23456780;
$epsilon = 0.00001;

if(abs($a-$b) < $epsilon) {
    echo "true";
}
?>

NaN

قد تؤدي بعض العمليات الحسابية إلى قيم تُمثَّل بالثابت NAN، وهذا بسبب أن نتيجة غير معرّفة أو غير قابلة للتمثيل في العمليات الحسابية على الأعداد العشرية. 

أي نوع من المقارنة بين القيمة NAN وأي قيمة أخرى –بما في ذلك القيمة NAN نفسها– (باستثناء TRUE) ستكون نتيجتها FALSE؛ ذلك لأنَّ NaN تمثل أي عدد من القيم المختلفة، لذا لا ينبغي مقارنتها مع أي قيمة أخرى، ويمكنك بدلًا من ذلك استخدام دالة is_nan()‎ للمقارنة.

مصادر