سؤال

أدناه هو اختبار كتلة من التعليمات البرمجية التي من المفترض أن تحدد المعادلة 2 الزوجي في إطار التسامح.

double lhs_1 = 0.02;
double lhs_2 = 0.04;
double rhs = 0.03;
double tolerance = 0.01;

bool is_match_1 = (abs(lhs_1 - rhs) <= tolerance);
bool is_match_2 = (abs(lhs_2 - rhs) <= tolerance);

ومع ذلك is_match_2 تبين كاذبة حيث is_match_1 اتضح صحيح.أنا أفهم أن الأرقام المخزنة في جهاز الكمبيوتر هي سرية القيم وليس مستمر.شخص ما يمكن أن تشترك في الحل ؟ أود أن يخطئ على جانب من اجتياز الاختبار في حدود المعقول.هل هناك طريقة لزيادة قيمة مزدوجة 1 مهما كانت الدقة يضم حاليا (أنا لست على دراية مع تخطيط بت مزدوجة)?لأنه ربما زيادة قيمة التسامح أن تسمح لهذا تحبب المسألة.

تحرير:

عندما يكون هذا هو حقا نفذت المستخدم تحديد المدخلات و التحمل, لذا أنا فقط أحاول أن أقدم لهم الناتج المتوقع لأي قيم دخولهم.

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

المحلول

للأسف لا يوجد "جيدة" قواعد اختيار التسامح.

لديك تحت تصرفكم "آلة إبسيلون"

double epsilon = std::numeric_limits<double>::epsilon()

الذي هو أصغر من القيمة التي تضاف إلى واحد يعطي نتيجة مختلفة عن بعضها.

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

bool fuzzy_equals(double a, double b)
{
    static const double eps = std::numeric_limits<double>::epsilon();
    return std::fabs(b - a) < 1024 * eps * std::max(a, b);
}

يعمل بشكل جيد في كثير من الحالات.يمكنك ضبط 1024 أحب القوى اثنين ولكن قد لا.القيمة الفعلية التي تختارها هي المشكلة التي تعتمد على.ابسيلون على الزوجي حوالي 10^-16 ، حتى 1024 صغيرة جدا, وسوف تحتاج إلى عدد أكبر في كثير من الحالات (أي العملية ، بما في ذلك ناقص العملية داخل fuzzy_equals سوف "تأكل" ابسيلون -- أنها يمكن أن تلغي ، ولكن في المتوسط ، n عمليات يعني sqrt(n) * epsilon الدقة, حتى 1024 يتوافق مع المتوقع الدقة بعد مليون العمليات).

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

bool fuzzy_equals2(double a, double b)
{
    static const double eps = std::numeric_limits<double>::epsilon();
    return std::fabs(b - a) < 1024 * std::sqrt(eps) * std::max(a, b);
}

أنا غالبا ما تستخدم وظائف أخرى ، مثل std::pow(eps, something), أو حتى -1 / std::log(eps).هذا يعتمد على ما قبل المعلومات التي يمكن أن تجنيها من هذه المشكلة و ما هو الخطأ أنا نتوقع.

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

باختصار, لا يوجد حجم واحد يناسب الجميع القاعدة.عليك أن تختار اعتمادا على المشكلة

نصائح أخرى

نقطة كاملة من وجود التسامح هو تجنب الشيكات المساواة واضحة.إنهم لا يعملون حقا من أجل الزوجي، حيث تعلمت للتو بالطريقة الصعبة.في عالم الزوجي، 1 + 1 قد لا يساوي 2 (على أنه داخليا، قد يكون الأمر مثل 1.99999743).

حتى "الفرق يساوي التسامح" ليست حالة موثوقة.يجب أن يكون التسامح 1-2 أوامر من الحجم أصغر من الفرق المعقول بين القيم، على عكس نفس الفرق المتوقع .لذلك إذا كنت تريد التحقق مما إذا كان LHS_2 - RHS يساوي RHS - LHS_1 داخل التسامح، فإن الشيك التالي من شأنه أن يخدمك بشكل أفضل: giveacodicetagpre.

التسامح الخاص بك هو بالفعل فضفاض جدا - 0.01 ضخمة مقارنة بالأرقام التي تقارنها.فقط افتحه حتى 0.01000001 وستكون بخير.

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