استثناء عائم باستخدام برنامج التحويل البرمجي للمحكمة الجنائية الدولية

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

سؤال

أقوم بتجميع الكود الخاص بي عبر الأمر التالي:

icc -ltbb test.cxx -o test

ثم عندما أقوم بتشغيل البرنامج:

time ./mp6 100 > output.modified
Floating exception
4.871u 0.405s 0:05.28 99.8%     0+0k 0+0io 0pf+0w

أحصل على "استثناء عائم". هذا التالي هو رمز في C ++ كان لدي قبل الاستثناء وبعد:

// before
if (j < E[i]) {
   temp += foo(0, trr[i], ex[i+j*N]);
}

// after
temp += (j < E[i])*foo(0, trr[i], ex[i+j*N]);

هذا الجبر المنطقي ... لذلك (j <e [i]) سيكون إما 0 أو 1 ، وبالتالي فإن الضرب ينتج إما في 0 أو نتيجة foo (). لا أرى لماذا هذا من شأنه أن يسبب استثناء عائم. هذا ما يفعله Foo ():

int foo(int s, int t, int e) {
    switch(s % 4) {
        case 0:
            return abs(t - e)/e;
        case 1:
            return (t == e) ? 0 : 1;
        case 2:
            return (t < e) ? 5 : (t - e)/t;
        case 3:
            return abs(t - e)/t;
    }
    return 0;
}

FOO () ليست وظيفة كتبتها ، لذا لست متأكدًا جدًا من ما يفعله ... لكنني لا أعتقد أن المشكلة هي مع الوظيفة FOO (). هل هناك شيء حول الجبر المنطقي لا أفهمه أو شيء يعمل بشكل مختلف في C ++ عما أعرفه؟ أي أفكار لماذا هذا يسبب استثناء؟

شكرا ، هريستو

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

المحلول

من المؤكد أنك تقسم على الصفر في foo.

برنامج بسيط لـ

int main()
{
    int bad = 0;
    return 25/bad;
}

كما يطبع

Floating point exception

على نظامي.

لذلك ، يجب عليك التحقق مما إذا كان e هو 0 عندما s % 4 هو الصفر ، أو ما إذا كان t هو 0 عندما s % 4 هو 2 أو 3. ثم ارجع أي قيمة منطقية لموقفك بدلاً من محاولة الانقسام على الصفر.


HRISTO: سيظل C ++ تقييم الجانب الأيمن للضرب حتى لو كان الجانب الأيسر صفرًا. لا يهم أن النتيجة يجب ان يكون صفر؛ من المهم ذلك foo تم استدعاؤه وتقييمه وتسبب في خطأ.

مصدر العينة:

#include <iostream>
int maybe_cause_exception(bool cause_it)
{
    int divisor = cause_it ? 0 : 10;
    return 10 / divisor;
}

int main()
{
    std::cout << "Do not raise exception: " << maybe_cause_exception(false) << std::endl;

    int x = 0;

    std::cout << "Before 'if' statement..." << std::endl;

    if(x)
    {
        std::cout << "Inside if: " << maybe_cause_exception(true) << std::endl;
    }

    std::cout << "Past 'if' statement." << std::endl;

    std::cout << "Cause exception: " << x * maybe_cause_exception(true) << std::endl;

    return 0;
}

انتاج:

Do not raise exception: 1

Before 'if' statement...

Past 'if' statement.

Floating point exception

نصائح أخرى

هل من الممكن أن تقسم على 0؟ يمكن أن يكون تقسيم عدد صحيح بمقدار 0 يسير على السطح كـ "استثناء عائم".

عندما يكون لديك if, ، لم يتم الحساب إذا حدث تقسيم بحلول 0. عند القيام بـ "الجبر المنطقي" ، يتم الحساب بغض النظر ، مما يؤدي إلى فجوة على خطأ 0.

أنت تفكر في أنه سيكون temp += 0*foo(...); لذلك لا يحتاج إلى استدعاء FOO (لأن 0 مرات سيكون أي شيء دائمًا 0) ، ولكن هذا ليس كيف يعمل المترجم. كلا جانبي أ * يجب تقييمها.

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


الطريقة الأكثر محمولة لتحديد ما إذا كان قد حدثت شرط استثناء في نقطة العائمة وسببها هو استخدام مرافق استثناء الفاصلة العائمة التي توفرها C99 In fenv.h. هناك 11 وظيفة محددة في fenv.h لمعالجة بيئة النقطة العائمة (انظر FENV (3) صفحة الرجل). قد تجد أيضًا هذه المقالة أن تكون ذات أهمية.


على أنظمة POSIX المتوافقة ، SIGFPE يتم إرسالها إلى عملية عندما تقوم في عملية حسابية خاطئة وهذا لا يتضمن بالضرورة الحساب العائم. إذا SIGFPE يتم التعامل مع الإشارة و SA_SIGINFO تم تحديده في sa_flags للدعوة إلى sigaction(2), ، ال si_code عضو في siginfo_t يجب أن يحدد الهيكل سبب الخطأ.

من ويكيبيديا SIGFPE مقالة - سلعة:

تتمثل الإشراف الشائع في النظر في الانقسام إلى الصفر المصدر الوحيد لظروف SIGFPE. في بعض البنى (بما في ذلك IA-32بحاجة لمصدر) ، تقسيم عدد صحيح من int_min ، أصغر قيمة عدد صحيح سلبي تمثيلا ، من خلال −1 يؤدي إلى الإشارة لأن الحاصل ، الرقم الإيجابي ، غير ممثل.

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

لا يزال بإمكانك استخدام خدعة الضرب ، إذا قمت بتحويل قاسم قليلاً. بدلاً من x/t استعمال x/(t + !t) الذي لا يؤثر على أي شيء إذا كان المقام غير صفري (أنت تضيف صفرًا بعد ذلك) ولكنك تسمح بمقام t = 0 لتكون حساب ، ثم رميها بالضرب على الصفر.

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

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