double.epsilon للمساواة، أكبر من، أقل من، أقل من أو يساوي، أكبر من أو يساوي

StackOverflow https://stackoverflow.com/questions/2411392

  •  18-09-2019
  •  | 
  •  

سؤال

http://msdn.microsoft.com/en-us/library/system.double.epsilon.aspx.

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

فهل هذا ليس حقا EPSILON التي يمكن استخدامها للمقارنات؟ أنا لا أفهم حقا صياغة MSDN.

هل يمكن استخدامها كإبسيلون في الأمثلة هنا؟ - ما هي الطريقة الأكثر فعالية للطفو والمقارنة المزدوجة؟

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

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

المحلول

لا أدري، لا أعرف ماذا او ما كانوا يدخنون عندما كتبوا ذلك. Double.Epsilon هي أصغر قيمة ذات قيمة فاصلة غير مشروعة غير شريكة ليست 0. كل ما تعرفه هو أنه، إذا كان هناك خطأ اقتطاع، فستكون دائما أكبر من هذه القيمة. أكبر بكثير.

ال System.Double يمكن أن يمثل نوع القيم الدقيق حتى 15 رقما. لذلك تقدير أول طلب بسيط إذا كانت قيمة مزدوجة x يساوي بعض الثابت هو استخدام EPSILON ثابت * 1E-15

public static bool AboutEqual(double x, double y) {
    double epsilon = Math.Max(Math.Abs(x), Math.Abs(y)) * 1E-15;
    return Math.Abs(x - y) <= epsilon;
}

عليك أن تراقب أن أخطاء اقتطاع يمكن أن تتراكم. إذا كان كل من x و y يتم حساب القيم ثم عليك زيادة Epsilon.

نصائح أخرى

أود أن أتأكد من أن لدي تطبيق قوي للمساواة، أكبر من، أقل من، أقل من أو يساوي، وأكبر من أو يساوي.

أنت تستخدم الحساب العائم الثنائي.

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

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

تتمتع قياسات الكميات المادية دائما بدقة معينة، اعتمادا على دقة الجهاز المستخدمة لقياسها.

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

لذلك، عند مقارنة كميين للمساواة، فإن الدلالات المرغوبة هي القول "هل هذه الكمان متساوية في أشرطة الخطأ المحددة من قبل كل قياس؟"

حتى الآن لدينا إجابة على سؤالك. ما يجب عليك فعله هو تتبع ما هو الخطأ في كل كمية؛ على سبيل المثال، ارتفاع المبنى "في غضون 0.01 من 123.56 متر" لأنك تعلم أن هذا هو مدى دقة القياس. إذا حصلت بعد ذلك على قياس آخر وهو 123.5587 وتريد أن تعرف ما إذا كانت القياسات "متساوية" ضمن تفاصيل الخطأ، ثم قم بالطرح ومعرفة ما إذا كان يسقط في تسامح الخطأ. في هذه الحالة، فإنه لا. إذا كانت القياسات دقيقة في الواقع إلى Micrometre، فهي ليست متساوية.

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

إذا كان لديك قيمتان مزدوجتان قيمتان من 1.0، لكنها تختلف فقط في بت فقط بتهم أقل أهمية، فستكون الفرق بينهما العديد من أوامر من حيث الحجم أكبر من Double.epsilon. في الواقع، الفرق هو 324 أوامر عشرية من الحجم. هذا بسبب تأثير الجزء الأساسي. يحتوي Double.EPSILON على أسلوب سلبي ضخم عليه، في حين أن 1.0 يحتوي على عرض صفر (بعد إزالة التحيزات، بالطبع).

إذا كنت ترغب في مقارنة قيمتين مماثلة للمساواة، فستحتاج إلى اختيار قيمة EPSILON مخصصة مناسبة لحجم أوامر حجم القيم المقارنة.

إذا كانت القيم المزدوجة التي تقارنها بالقرب من 1.0. ثم تكون قيمة البتة الأقل سيكلية بالقرب من 0.0000000000000001. إذا كانت القيم المزدوجة التي تقارنها هي في Quadsillionions، فيمكن أن تكون قيمة القليل الأقل أهمية بقدر ألف. لا يمكن استخدام أي قيمة واحدة لإبرسيلون مقارنات المساواة في كل من هذه الظروف.

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

private bool IsApproximatelyEqual(double x, double y, double acceptableVariance)
{
     double variance = x > y ? x - y : y - x;
     return variance < acceptableVariance;

     //or
     //return Math.Abs(x - y) < acceptableVariance;
}

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

لماذا لا يعرف .NET Framework شيئا مثل

bool IsApproximatelyEqual(double value, double permittedVariance);

خارج عن ارادتي.

أعتقد أن البتات ذات الصلة في رابط MSDN الذي نشرته هو:

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

ملاحظة: قيمة خاصية Epsilon ليست تعادل آلة EPSILON، والتي تمثل الحد العلوي من الخطأ النسبي بسبب التقريب في الحساب العائم.

لا يتم تعريف هذه القيمة بأنها أصغر عدد إيجابي X، مثل أن X + 1.0 لا يساوي 1.0، لذلك لا يمكن استخدام Double.Epsilon ل "المساواة تقريبا". لا يوجد ثابت في الإطار الذي تكون قيمته أصغر عدد إيجابي X، مثل أن X + 1.0 لا يساوي 1.0.

يجب أن أقول، هذا يفاجئني. لقد افترضت أن Double.epsilon كان ما يعادل DBL_EPSILON في C / C ++ - من الواضح أنه لا!

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

أنا استخدم ما يلي

public static class MathUtil {
    /// <summary>
    /// smallest such that 1.0+EpsilonF != 1.0
    /// </summary>
    public const float EpsilonF = 1.192092896e-07F;

    /// <summary>
    /// smallest such that 1.0+EpsilonD != 1.0
    /// </summary>
    public const double EpsilonD = 2.2204460492503131e-016;

    [MethodImpl( MethodImplOptions.AggressiveInlining )]
    public static bool IsZero( this double value ) {
        return value < EpsilonD && value > -EpsilonD;
    }

    [MethodImpl( MethodImplOptions.AggressiveInlining )]
    public static int Sign( this double value ) {
        if ( value < -EpsilonD ) {
            return -1;
        }
        if ( value > EpsilonD )
            return 1;
        return 0;
    }

وإذا كنت ترغب في التحقق من المساواة بين اثنين من الزوجي "A" و "B"، يمكنك استخدامها

(a-b).IsZero();

وإذا كنت ترغب في الحصول على نتيجة المقارنة، استخدم

(a-b).Sign();

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

إليك بعض الكود الذي يشمل مرتين ضمن مجموعة أدوات التحكم Silverlight:

    public static bool AreClose(double value1, double value2)
    {
        //in case they are Infinities (then epsilon check does not work)
        if(value1 == value2) return true;
        // This computes (|value1-value2| / (|value1| + |value2| + 10.0)) < DBL_EPSILON
        double eps = (Math.Abs(value1) + Math.Abs(value2) + 10.0) * DBL_EPSILON;
        double delta = value1 - value2;
        return(-eps < delta) && (eps > delta);
    }

في مكان واحد يستخدمونه 1e-6 لإبرسيلون في آخر يستخدمون 1.192093E-07. وبعد سوف ترغب في اختيار Epsilon الخاصة بك.

لا يوجد خيار لديك لحسابه بنفسك أو تحديد ثابت.

double calculateMachineEpsilon() {
    double result = 1.0;
    double one = 1.0/256;

    while(one + result/2.0 != 1.0) {
        result/=2.0;
    }
    return result;
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top