سؤال

لدي وظيفة C # بسيطة:

public static double Floor(double value, double step)
{
    return Math.Floor(value / step) * step;
}

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

[TestMethod()]
public void FloorTest()
{
    int decimals = 6;
    double value = 5F;
    double step = 2F;
    double expected = 4F;
    double actual = Class.Floor(value, step);
    Assert.AreEqual(expected, actual);
    value = -11.5F;
    step = 1.1F;
    expected = -12.1F;
    actual = Class.Floor(value, step);
    Assert.AreEqual(Math.Round(expected, decimals),Math.Round(actual, decimals));
    Assert.AreEqual(expected, actual);
}

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

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

ملحوظة في رمز الاختبار الخاص بي، كتبت لاحقة "F" (ثابتة تعويم صريح) حيث قصدت "D" (مزدوج)، لذلك إذا قمت بتغيير ذلك، يمكنني الحصول على مزيد من الدقة.

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

المحلول

إذا حذفت كل postfixes f (أي -12.1 بدلا من -12.1F) سوف تحصل على المساواة لبضع أرقام أكثر. يطفو الثوابت الخاصة بك (وخاصة القيم المتوقعة) الآن بسبب F. وبعد إذا كنت تفعل ذلك عن قصد، فيرجى توضيح ذلك.

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

نصائح أخرى

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

العائمة نقطة الحساب على أجهزة الكمبيوتر ليست العلوم الدقيقة :).

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

http://en.wikipedia.org/wiki/floating_point#accuracy_problems.

على سبيل المثال، يعني عدم إمكانية تمثيل 0.1 و 0.01 (في ثنائي) أن نتيجة محاولة مربعة 0.1 ليست 0.01 ولا الرقم الممثل الأقرب إليه.

فقط استخدم النقطة العائمة إذا كنت تريد تفسير الجهاز (ثنائي) من أنظمة الأرقام. لا يمكنك تمثيل 10 سنتات.

إذا كنت تريد الدقة، استخدم النظام. إذا كنت تريد السرعة، استخدم System.Duble (أو system.float.float). لا تكون أرقام النقاط العائمة أرقام "دقيقة لانهائية"، وبالتالي يجب أن تتضمن المساواة التسامح. طالما أن الأرقام الخاصة بك لديها عدد معقول من الأرقام الكبيرة، فهذه موافق.

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

يرى هذه الإجابة (أيضا مني) لتحليل مفصل لكيفية التأثير الدقة على نتائج العمليات الرياضية الخاصة بك.

تحقق من الإجابات على هذا السؤال: هل من الآمن التحقق من قيم النقطة العائمة للمساواة إلى 0؟

حقا، فقط تحقق من "داخل التسامح من ..."

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

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

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

public static double roundValue(double rawValue, double valueTick)
{
    if (valueTick <= 0.0) return 0.0;

    Decimal val = new Decimal(rawValue);
    Decimal step = new Decimal(valueTick);
    Decimal modulo = Decimal.Round(Decimal.Divide(val,step));

    return Decimal.ToDouble(Decimal.Multiply(modulo, step));
}

في بعض الأحيان تكون النتيجة أكثر دقة مما تتوقع من صارمة: FP IEEE 754. هذا لأن HW يستخدم المزيد من البتات للحساب. يرى C # المواصفات و هذه المقالة

تحتوي Java على كلمة رئيسية CentfP و C ++ لديك مفاتيح التحويل البرمجي. افتقد هذا الخيار في .NET

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