سؤال

ما هي أفضل طريقة مقارنة IEEE يطفو الزوجي من أجل المساواة ؟ لقد سمعت من عدة طرق ، ولكن أردت أن أرى ماذا المجتمع الفكر.

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

المحلول

أفضل نهج أعتقد هو مقارنة ULPs.

bool is_nan(float f)
{
    return (*reinterpret_cast<unsigned __int32*>(&f) & 0x7f800000) == 0x7f800000 && (*reinterpret_cast<unsigned __int32*>(&f) & 0x007fffff) != 0;
}

bool is_finite(float f)
{
    return (*reinterpret_cast<unsigned __int32*>(&f) & 0x7f800000) != 0x7f800000;
}

// if this symbol is defined, NaNs are never equal to anything (as is normal in IEEE floating point)
// if this symbol is not defined, NaNs are hugely different from regular numbers, but might be equal to each other
#define UNEQUAL_NANS 1
// if this symbol is defined, infinites are never equal to finite numbers (as they're unimaginably greater)
// if this symbol is not defined, infinities are 1 ULP away from +/- FLT_MAX
#define INFINITE_INFINITIES 1

// test whether two IEEE floats are within a specified number of representable values of each other
// This depends on the fact that IEEE floats are properly ordered when treated as signed magnitude integers
bool equal_float(float lhs, float rhs, unsigned __int32 max_ulp_difference)
{
#ifdef UNEQUAL_NANS
    if(is_nan(lhs) || is_nan(rhs))
    {
        return false;
    }
#endif
#ifdef INFINITE_INFINITIES
    if((is_finite(lhs) && !is_finite(rhs)) || (!is_finite(lhs) && is_finite(rhs)))
    {
        return false;
    }
#endif
    signed __int32 left(*reinterpret_cast<signed __int32*>(&lhs));
    // transform signed magnitude ints into 2s complement signed ints
    if(left < 0)
    {
        left = 0x80000000 - left;
    }
    signed __int32 right(*reinterpret_cast<signed __int32*>(&rhs));
    // transform signed magnitude ints into 2s complement signed ints
    if(right < 0)
    {
        right = 0x80000000 - right;
    }
    if(static_cast<unsigned __int32>(std::abs(left - right)) <= max_ulp_difference)
    {
        return true;
    }
    return false;
}

تقنية مماثلة يمكن أن تستخدم في الزوجي.هو خدعة لتحويل يطفو بحيث انهم أمر (كما لو الصحيحه) ثم انظر فقط كيف مختلفة هي.

ليس لدي أي فكرة عن سبب هذا الشيء هو تعبث يؤكد.تحرير:ربما هذا هو مجرد أثر من المعاينة.وهذا موافق ثم.

نصائح أخرى

الإصدار الحالي أنا باستخدام هذا

bool is_equals(float A, float B,
               float maxRelativeError, float maxAbsoluteError)
{

  if (fabs(A - B) < maxAbsoluteError)
    return true;

  float relativeError;
  if (fabs(B) > fabs(A))
    relativeError = fabs((A - B) / B);
  else
    relativeError = fabs((A - B) / A);

  if (relativeError <= maxRelativeError)
    return true;

  return false;
}

يبدو أن تأخذ الرعاية من معظم المشاكل من خلال الجمع بين النسبي و المطلق خطأ التسامح.هو ULP نهج أفضل ؟ إذا كان الأمر كذلك, لماذا ؟

@DrPizza:أنا لا أداء المعلم ولكن أتوقع نقطة ثابتة العمليات أسرع من عمليات النقطة العائمة (في معظم الحالات).

بل يعتمد على ما تقومون به معهم.ثابت-نوع نقطة مع نفس النطاق مثل IEEE تطفو سيكون عدد مرات عديدة أبطأ (في كثير من الأوقات أكبر).

أشياء مناسبة يطفو:

3D الرسومات والفيزياء/الهندسة, محاكاة, محاكاة مناخية....

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

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

  • y = بيتا*y + الفا*A*x
  • y = بيتا*y + الفا*A^T*x
  • y = بيتا*y + الفا*أ^ح*x

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

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

P. S.:

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

  • على الرغم من أن LAPACK هو مكتوب في Fortran المنطق هو نفس إذا كنت تستخدم لغات البرمجة الأخرى العددي البرمجيات.

يا إلهي أرجوك لا تفسير تطفو بت كما رجات إلا إذا كنت تعمل على P6 أو في وقت سابق.

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

أيهو ثمن يستحق الدفع.

يبدو أن تأخذ الرعاية من معظم المشاكل من خلال الجمع بين النسبي و المطلق خطأ التسامح.هو ULP نهج أفضل ؟ إذا كان الأمر كذلك, لماذا ؟

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

إذا كان لديك نقطة عائمة الأخطاء لديك المزيد من المشاكل من هذا.على الرغم من أنني أعتقد أن هذا هو ما يصل إلى منظور شخصي.

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

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

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

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

@DrPizza:أنا لا أداء المعلم ولكن أتوقع نقطة ثابتة العمليات أسرع من عمليات النقطة العائمة (في معظم الحالات).

@كريغ H:بالتأكيد.أنا بخير مع ذلك الطباعة.إذا أ أو ب متجر المال ومن ثم ينبغي أن تكون ممثلة في نقطة ثابتة.أنا تكافح من أجل التفكير في العالم الحقيقي سبيل المثال أين هذا المنطق يجب أن يكون المتحالفة يطفو.أشياء مناسبة يطفو:

  • الأوزان
  • صفوف
  • المسافات
  • العالم الحقيقي القيم (مثل من ADC)

كل هذه الأشياء إما أن كثيرا ثم أرقام ببساطة تقديم النتائج للمستخدم الإنسان أو التفسير أو إجراء المقارنة البيان (حتى لو كان مثل هذا البيان هو "هذا الشيء هو داخل 0.001 من هذا الشيء الآخر").مقارن بيان مثل الألغام هو مفيد فقط في سياق الخوارزمية:فإن "داخل 0.001" جزء يعتمد على ما المادية السؤال كنت طالبا.أن بلدي 0.02.أو ينبغي أن أقول 2/100ths?

بل يعتمد على ما كنت تفعل معهم.ثابت-نوع نقطة مع نفس النطاق مثل IEEE تطفو سيكون عدد مرات عديدة أبطأ (و عدة مرات أكبر).

حسنا, ولكن إذا كنت تريد متناهي الصغر صغيرة بت القرار ثم أعود إلى بلدي الأصلي النقطة:== و != لا معنى لها في سياق مثل هذه المشكلة.

الباحث يتيح لي التعبير عن ~10^9 القيم (بغض النظر عن المدى) الذي يبدو بما فيه الكفاية على أي حالة حيث كنت الرعاية حول اثنين منهم متساوية.و إذا كان هذا لا يكفي ، استخدام نظام تشغيل 64 بت و كنت قد حصلت على حوالي 10^19 متميزة القيم.

أستطيع التعبير عن القيم مجموعة من 0 إلى 10^200 (على سبيل المثال) في الباحث ، هو فقط قليلا القرار الذي يعاني (القرار سيكون أكبر من 1, ولكن, مرة أخرى, لا يوجد تطبيق له هذا النوع من مجموعة فضلا عن هذا النوع من القرار).

لتلخيص, أعتقد في كل الحالات واحدة إما يمثل سلسلة متصلة من القيم في هذه الحالة != و == ليست ذات صلة ، أو أحد يمثل مجموعة ثابتة من القيم التي يمكن تعيينها إلى int (أو آخر ثابت-نوع الدقة).

الباحث يتيح لي التعبير عن ~10^9 القيم (بغض النظر عن المدى) الذي يبدو مثل بما فيه الكفاية على أي حالة حيث كنت أن تهتم اثنين منهم على قدم المساواة.و إذا كان هذا لا يكفي, استخدام 64 بت نظام التشغيل لديك حوالي 10^19 قيم مميزة.

أنا فعلا ضرب هذا الحد...كنت أحاول أن توفق مرات في ps و الوقت في الساعة دورات في محاكاة حيث يمكنك بسهولة ضرب 10^10 دورات.بغض النظر عن ما فعلته أنا بسرعة جدا فاضت سقيم مجموعة من 64 بت الصحيحه...10^19 ليس بقدر ما كنت أعتقد أنه هو ، أعطني 128 بت الحوسبة الآن!

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

ثم الأشياء تحويلها إلى أعداد مقارنة إلخ.

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

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

ربما علي أن أشرح المشكلة بشكل أفضل.في C++, التعليمة البرمجية التالية:

#include <iostream>

using namespace std;


int main()
{
  float a = 1.0;
  float b = 0.0;

  for(int i=0;i<10;++i)
  {
    b+=0.1;
  }

  if(a != b)
  {
    cout << "Something is wrong" << endl;
  }

  return 1;
}

طباعة عبارة "هناك شيئا خطأ".أنت تقول أنه يجب ؟

يا إلهي أرجوك لا تفسير تطفو بت كما رجات إلا إذا كنت تعمل على P6 أو في وقت سابق.

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

إذا كان لديك نقطة عائمة الأخطاء لديك المزيد من المشاكل من هذا.على الرغم من أنني أعتقد أن هذا هو ما يصل إلى منظور شخصي.

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