سؤال

حصلت على مشكلة حسابية رياضية أخرى مرة أخرى.

$a = 34.56

$b = 34.55

$a القيام ببعض الحسابات للحصول على هذا الرقم

$b يقوم بالتقريب لأقرب 0.05 للحصول على هذا الرقم

ما يحدث هو

$c = $b - $a

من المفترض أن أكون -0.01، لكنني أردد صدى $c يظهر -0.00988888888888

أحاول استخدام نumber_format($c, 2), ولكن الناتج هو 0.00

كيف يمكنني التأكد $a و $b هو بالضبط رقمان عشريان، ولا يوجد رقم مخفي في الخلف.

في معرفتي بـ php، فإن number_format هو الوحيد القادر على تنسيق العرض، لكن القيمة ليست في الواقع رقمين عشريين،

آمل أن أتمكن من الحصول على المساعدة من هنا.هذا أحبطني حقا.

هل كانت مفيدة؟

المحلول

sprintf ("%.2f", $c);

وتتمثل

وأرقام النقطة العائمة في التدوين IEEE بناء على صلاحيات 2، لذلك تنتهي أرقام عشرية قد لا يكون رقم ثنائي تنتهي، هذا هو السبب في أن تحصل على أرقام زائدة.

وكما اقترح متغير طول المبرمج، إذا كنت تعرف الدقة التي تريدها، وأنه لا تغيير (على سبيل المثال عندما كنت تتعامل مع المال) قد يكون من الأفضل لمجرد استخدام أرقام نقطة ثابتة أي تعبير عن الأرقام كما سنتا بدلا من الدولارات

$a = 3456;

$b = 3455;

$c = $b - $a;

sprintf ("%.2f", $c/100.0);

وبهذه الطريقة، سوف لا يكون لديك أي أخطاء التقريب إذا كنت تفعل الكثير من العمليات الحسابية قبل الطباعة.

نصائح أخرى

يستخدم round():

$c = round($b - $a, 2);

ملحوظة: يمكنك أيضًا اختيار وضع التقريب حسب الاقتضاء.

يحرر: طيب أنا لا أفهم ما sprintf() يفعل ذلك number_format() ليس:

$c = number_format($b - $a, 2);

ضد

$c = sprintf("%.2f", $b - $a);

?

الحساب الأصلي:

$a = 34.56;
$b = 34.55;
$c = $b - $a; // -0.010000000000005    

يعمل كما هو متوقع (!استخدم دائمًا وظائف BC لحسابات الأعداد الحقيقية، فالمشكلة تتعلق بجميع الأنظمة الأساسية المستندة إلى لغة C):

$a = '34.56';
$b = '34.55';
$c = bcsub($b, $a, 4); // -0.0100    

وركضت أيضا في هذه المسألة مؤخرا عند القيام الحسابات مع عوامات. على سبيل المثال، كان لي 2 يطفو أنه عندما طرح وتنسيق، وكانت قيمة -0.00.

$floatOne = 267.58;
$floatTwo = 267.58;
$result = number_format($floatOne - floatTwo, 2);
print $result; //printed a string -0.00

ما فعلته كان:

$result = abs($floatOne - $floatTwo);// Made the number positive
print money_format('%i', $result); // printed the desired precision 0.00

في حل بي وأنا أعلم أن floatOne لن يكون أقل من floatTwo. و money_format يعرف وظيفة إلا إذا كان النظام قد strfmon القدرات، لا نوافذ لا.

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

وعلى سبيل المثال، إذا كنت تفعل الحسابات في يطفو represeting دولار (أو العملة المفضلة لديك)، قد ترغب في القيام به في الواقع الحسابات الخاصة بك في سنتا صحيح.

ويمكنك تجنب بعناية جدا كل هذه القضايا ببساطة عن طريق استخدام المكتبة bcmath.

وتذكر فقط لقراءة الوثائق والحرص على ما إذا كنت تمرير الوسائط كسلاسل أو أنواع البيانات الرقمية.

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

لتوضيح المشكلة، وسأشرح لماذا مع مثال بسيط أدناه.

لا يرتبط ذلك مباشرة إلى PHP وأنها ليست علة. ومع ذلك، يجب أن يكون كل مبرمج على بينة من هذه المسألة.

وهذه المشكلة حتى استغرق الكثير من الأرواح قبل عقدين من الزمن.

في 25 فبراير 1991 هذه المشكلة في عائم حساب رقم في MIM-104 بطارية صواريخ باتريوت منعتها اعتراض صاروخ سكود الواردة في الظهران، المملكة العربية السعودية، والمساهمة في وفاة 28 جنديا من ال14 التموين مفرزة للجيش الامريكى.

ولكن لماذا يحدث ذلك؟

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

ومجرد مثال بسيط:

$a = '36';
$b = '-35.99';
echo ($a + $b);

وأنت تتوقع أن طباعة 0.01، أليس كذلك؟ لكنها ستطبع إجابة غريبة جدا مثل ،009999999999998

ومثل الأرقام الأخرى، يتم تخزين أرقام النقطة العائمة مزدوجة أو تطفو في الذاكرة كسلسلة من ل0 و 1 '. كيف النقطة العائمة يختلف عن عدد صحيح هو في كيفية تفسير 0 و1 عندما نريد أن ننظر إليها. هناك العديد من المعايير كيفية تخزينها.

وعادة ما تكون معبأة

وأرقام الفاصلة العائمة في مسند الكمبيوتر مثل بت تسجيل، مجال الأس، وsignificand أو العشري، من اليسار إلى اليمين ....

والأرقام العشرية ليست ممثلة تمثيلا جيدا في ثنائي بسبب عدم وجود مساحة كافية. لذا، uou لا يستطيعون التعبير عن 1/3 بالضبط كما انها 0.3333333 ...، أليس كذلك؟ لماذا نحن لا يمكن أن تمثل 0.01 كرقم تعويم ثنائي لنفس السبب. 1/100 غير 0.00000010100011110101110000 ..... مع تكرار +10100011110101110000.

إذا يتم الاحتفاظ 0.01 في شكل مبسط واقتطاع نظام +01000111101011100001010 في ثنائي، عندما يتم ترجمته إلى عشري، فإنه سيتم قراءة مثل 0.0099999 .... وفقا لنظام (حواسيب 64BIT سوف تعطيك دقة أفضل بكثير من 32-بت). نظام التشغيل يقرر في هذه الحالة ما إذا كان لطباعته لأنه يرى أو كيفية جعله في أكثر الطريقة البشرية للقراءة. لذا، فمن كيف يريدون لتمثيلها تعتمد على الجهاز. ولكن يمكن أن تكون محمية في مستوى اللغة مع أساليب مختلفة.

إذا قمت بتهيئة نتيجة لذلك، number_format صدى (0.009999999999998، 2)؛ فإنه سيتم طباعة 0.01.

ولأن في هذه الحالة يمكنك إرشاد الكيفية التي ينبغي أن تقرأ وكيف الدقة التي تحتاجها.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top