objective c - معنى - ما مدى خطورة مقارنة قيم النقطة العائمة؟




معنى كلمة عنوان بالانجليزي (6)

[إن "الإجابة الصحيحة" تتمجد فوق تحديد K يؤدي اختيار K إلى الظهور كمجرد تخصيص مثل تحديد VISIBLE_SHIFT لكن تحديد K أقل وضوحًا لأنه بخلاف VISIBLE_SHIFT لا يكون مؤثراً على أي خاصية عرض. وهكذا اختر السم الخاص بك - حدد K أو حدد VISIBLE_SHIFT . VISIBLE_SHIFT هذه الإجابة إلى اختيار VISIBLE_SHIFT ثم توضح صعوبة تحديد K ]

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

#define VISIBLE_SHIFT    0.0001        // for example
if (fabs(theView.frame.origin.x) < VISIBLE_SHIFT) { /* ... */ }

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

الآن ، تقع "الإجابة الصحيحة" على K لذلك دعنا نستكشف التقاط K "الجواب الصحيح" أعلاه يقول:

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

لذلك نحن بحاجة K . إذا كان الحصول على K أكثر صعوبة ، أقل حدسية من اختيار VISIBLE_SHIFT ما الذي يناسبك. للعثور على K ، سنكتب برنامج اختبار يبحث في مجموعة من قيم K حتى نتمكن من رؤية كيف يتصرف. يجب أن يكون واضحًا كيفية اختيار K ، إذا كانت الإجابة الصحيحة قابلة للاستخدام. لا؟

سنستخدم ، كتفاصيل "الإجابة الصحيحة":

if (fabs(x-y) < K * DBL_EPSILON * fabs(x+y) || fabs(x-y) < DBL_MIN)

لنجرب كل قيم K:

#include <math.h>
#include <float.h>
#include <stdio.h>

void main (void)
{
  double x = 1e-13;
  double y = 0.0;

  double K = 1e22;
  int i = 0;

  for (; i < 32; i++, K = K/10.0)
    {
      printf ("K:%40.16lf -> ", K);

      if (fabs(x-y) < K * DBL_EPSILON * fabs(x+y) || fabs(x-y) < DBL_MIN)
        printf ("YES\n");
      else
        printf ("NO\n");
    }
}
[email protected]$ gcc -o test test.c
[email protected]$ ./test
K:10000000000000000000000.0000000000000000 -> YES
K: 1000000000000000000000.0000000000000000 -> YES
K:  100000000000000000000.0000000000000000 -> YES
K:   10000000000000000000.0000000000000000 -> YES
K:    1000000000000000000.0000000000000000 -> YES
K:     100000000000000000.0000000000000000 -> YES
K:      10000000000000000.0000000000000000 -> YES
K:       1000000000000000.0000000000000000 -> NO
K:        100000000000000.0000000000000000 -> NO
K:         10000000000000.0000000000000000 -> NO
K:          1000000000000.0000000000000000 -> NO
K:           100000000000.0000000000000000 -> NO
K:            10000000000.0000000000000000 -> NO
K:             1000000000.0000000000000000 -> NO
K:              100000000.0000000000000000 -> NO
K:               10000000.0000000000000000 -> NO
K:                1000000.0000000000000000 -> NO
K:                 100000.0000000000000000 -> NO
K:                  10000.0000000000000000 -> NO
K:                   1000.0000000000000000 -> NO
K:                    100.0000000000000000 -> NO
K:                     10.0000000000000000 -> NO
K:                      1.0000000000000000 -> NO
K:                      0.1000000000000000 -> NO
K:                      0.0100000000000000 -> NO
K:                      0.0010000000000000 -> NO
K:                      0.0001000000000000 -> NO
K:                      0.0000100000000000 -> NO
K:                      0.0000010000000000 -> NO
K:                      0.0000001000000000 -> NO
K:                      0.0000000100000000 -> NO
K:                      0.0000000010000000 -> NO

آه ، لذا يجب أن يكون K 1e16 أو أكبر إذا كنت أريد أن يكون 1e-13 "صفرًا".

لذا ، أود أن أقول إن لديك خيارين:

  1. قم بإجراء حساب epsilon بسيط باستخدام حكمك الهندسي لقيمة "epsilon" ، كما اقترحت. إذا كنت تقوم بعمل رسومات و "صفر" يعني أن يكون "تغيير مرئي" من فحص الأصول البصرية الخاصة بك (الصور ، إلخ) والحكم على ما يمكن أن يكون epsilon.
  2. لا تحاول إجراء أي حسابات عائمة حتى تقوم بقراءة مرجع الإجابة غير الحمولة (وحصلت على شهادة الدكتوراه في العملية) ثم استخدم حكمك غير البديهي لاختيار K

أعرف أن UIKit يستخدم CGFloat بسبب نظام الإحداثيات المستقلة.

ولكن في كل مرة أرغب في التحقق مما إذا كان frame.origin.x سبيل المثال هو 0 يجعلني أشعر بالمرض:

if (theView.frame.origin.x == 0) {
    // do important operation
}

أليس CGFloat عرضة CGFloat الزائفة عند المقارنة مع == ، <= ، >= ، < ، > ؟ وهي نقطة عائمة ولديها مشاكل عدم الدقة: 0.0000000000041 على سبيل المثال.

هل Objective-C التعامل مع هذا داخليا عند مقارنة أو يمكن أن يحدث أن origin.x الذي يقرأ صفر لا يقارن إلى 0 كما هو صحيح؟


أود أن أقول إن الشيء الصحيح هو إعلان كل رقم ككائن ، ثم تحديد ثلاثة أشياء في ذلك الكائن: 1) مشغل المساواة. 2) مجموعةأسلوب مقبولالتغير. 3) القيمة نفسها. ويعود عامل التساوي إلى true إذا كان الفرق المطلق بين قيمتين أقل من القيمة المحددة على أنها مقبولة.

يمكنك تصنيف الكائن لتلائم المشكلة. على سبيل المثال ، يمكن اعتبار القضبان المستديرة من المعدن ما بين 1 و 2 بوصة من قطر متساوٍ إذا اختلفت أقطارها بأقل من 0.0001 بوصة. لذلك يمكنك استدعاء setAcceptableDifference مع المعلمة 0.0001 ، ومن ثم استخدام مشغل المساواة بكل ثقة.


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

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

لذلك إذا كنت ترغب في اختبار ما إذا كانت نقطتك تقع خارج نطاق [0..width [range فهذا شيء جيد. تأكد فقط من تحديد التضمين بشكل متسق. على سبيل المثال ، دائمًا ما يتم تعريف داخل (x> = 0 && x <width). وينطبق نفس الشيء على اختبارات التقاطع أو الضربة.

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


السؤال الصحيح: كيف يمكن مقارنة النقاط في Cocoa Touch؟

الإجابة الصحيحة: CGPointEqualToPoint ().

سؤال مختلف: هل هناك قيمتان محسوبتان متشابهتان؟

الإجابة المنشورة هنا: إنهم ليسوا كذلك.

كيفية التحقق مما إذا كانت قريبة؟ إذا كنت تريد التحقق مما إذا كانت قريبة ، فلا تستخدم CGPointEqualToPoint (). ولكن ، لا تحقق لمعرفة ما إذا كانت قريبة. افعل شيئًا منطقيًا في العالم الحقيقي ، مثل التحقق لمعرفة ما إذا كانت النقطة أبعد من خط أو إذا كانت نقطة داخل الكرة.


نظرًا لأن الرقم 0 قابل للتمثيل تمامًا كرقم IEEE754 عائم (أو باستخدام أي تطبيق آخر لأرقام fp التي عملت بها) ، فمن المحتمل أن تكون المقارنة مع 0 آمنة. ومع ذلك ، قد تتعرض للعض ، إذا كان برنامجك يحسب قيمة ما (مثل theView.frame.origin.x ) التي لديك سبب للاعتقاد أنه يجب أن يكون 0 ولكن لا يمكن أن يضمن حسابك أن يكون 0.

لتوضيح القليل ، حساب مثل:

areal = 0.0

سوف (ما لم يتم تقسيم اللغة أو النظام الخاص بك) إنشاء قيمة بحيث (truel = = 0.0) ترجع true ولكن حساب آخر مثل

areal = 1.386 - 2.1*(0.66)

ربما لا.

إذا كنت تستطيع أن تؤكد لنفسك أن حساباتك تنتج قيمًا هي 0 (وليس فقط أنها تنتج قيمًا يجب أن تكون 0) ، فيمكنك المضي قدمًا ومقارنة قيم fp مع 0. إذا لم تتمكن من ضمان درجة الدرجات المطلوبة ، أفضل التمسك بالنهج المعتاد "المساواة المتسامحة".

في أسوأ الحالات ، يمكن أن تكون مقارنة قيم fp التي لا مبالاة فيها خطيرة للغاية: فكر في استخدام إلكترونيات الطيران ، وتوجيه الأسلحة ، وعمليات محطات توليد الطاقة ، والملاحة بالسيارة ، وتقريبا أي تطبيق يجتمع فيه الحساب الفعلي مع العالم الحقيقي.

لطيور غاضبة ، ليست خطيرة جدا.


يمكنك استخدام هذه الشفرة لمقارنة العوامة بصفر:

if ((int)(theView.frame.origin.x * 100) == 0) {
    // do important operation
}

هذا سوف يقارن مع دقة 0.1 ، وهذا يكفي ل CGFloat في هذه الحالة.





floating-accuracy