سؤال

لماذا هو إلزامي للاستخدام -ffast-math مع G ++ لتحقيق ضبط الحلقات باستخدام doubleس؟ أنا لا أحب -ffast-math لأنني لا أريد أن أفقد الدقة.

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

المحلول

أنت لا تفقد الدقة بالضرورة -ffast-math. يؤثر فقط على التعامل مع NaN, Inf وما إلى ذلك والترتيب الذي يتم فيه تنفيذ العمليات.

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

على سبيل المثال ، يقوم الرمز التالي بإجراء عملية التقريب f. ومع ذلك ، الاثنين f += g و f -= g من المحتمل أن تحصل العمليات على تحسينها بواسطة GCC:

static double moo(double f, double g)                                      
{                                                                          
    g *= 4503599627370496.0; // 2 ** 52                                    
    f += g;                                                                
    f -= g;                                                                
    return f;                                                            
}                                                                     

على x86_64 ، يمكنك استخدام هذا asm بيان لإرشاد GCC بعدم إجراء هذا التحسين:

static double moo(double f, double g)                                      
{                                                                          
    g *= 4503599627370496.0; // 2 ** 52                                    
    f += g;                                                                
    __asm__("" : "+x" (f));
    f -= g;
    return f;
}

ستحتاج إلى تكييف هذا لكل بنية ، لسوء الحظ. على PowerPC ، استخدم +f بدلاً من +x.

نصائح أخرى

من المحتمل جدًا لأن التقييم يعني أنه قد يكون لديك نتائج مختلفة ، أو قد تعني أنك تفوت إشارات/استثناءات النقطة العائمة.

إذا كنت تقوم بتجميع 32 بت X86 ، فستكون GCC و G ++ افتراضيًا لاستخدام X87 للرياضيات العائمة ، في 64 بت ، فهي افتراضية لـ SSE ، ومع ذلك ، يمكن لـ X87 أن تنتج قيمًا مختلفة لنفس الحساب بحيث يكون من غير المحتمل G ++ سوف تفكر في التفكير إذا كان لا يمكن أن تضمن أنك ستحصل على نفس النتائج ما لم تستخدم -ffast-math أو بعض الأعلام التي يتم تشغيلها.

في الأساس ، قد لا يكون الأمر يتعلق ببيئة النقطة العائمة للرمز المتجهي

-fno-math-errno -fno-trapping-math -fno-signaling-nans -fno-rounding-math

لكن ابحث أولاً عن تلك الخيارات وتأكد من أنها لن تؤثر على صحة البرنامج. -ffinite-math-only قد تساعد أيضا

لان -ffast-math تمكين المعاملات إعادة ترتيب الذي يسمح للعديد من التعليمات البرمجية أن تكون متجه.

على سبيل المثال لحساب هذا

sum = a[0] + a[1] + a[2] + a[3] + a[4] + a[5] + … a[99]

المترجم هو مطلوب للقيام بالإضافات بالتتابع بدون -ffast-math, ، لأن الرياضيات النقطة العائمة ليست مبتدرة ولا ترابطية.

هذا هو نفس السبب لماذا لا يمكن للمترجمين تحسين a*a*a*a*a*a إلى (a*a*a)*(a*a*a) بدون -ffast-math

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

ومع ذلك، إذا -ffast-math تم تمكينه ، يمكن حساب التعبير مثله (ينظر الى A7. Auto-Vectorization)

sum0 = a[0] + a[4] + a[ 8] + … a[96]
sum1 = a[1] + a[5] + a[ 9] + … a[97]
sum2 = a[2] + a[6] + a[10] + … a[98]
sum3 = a[3] + a[7] + a[11] + … a[99]
sum’ = sum0 + sum1 + sum2 + sum3

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

يفعل sum’ == sum؟ فقط اذا (a[0]+a[4]+…) + (a[1]+a[5]+…) + (a[2]+a[6]+…) + ([a[3]+a[7]+…) == a[0] + a[1] + a[2] + … هذا ينطبق تحت الارتباط ، الذي لا يطفو ، طوال الوقت. تحديد /fp:fast دع المترجم يحول الكود الخاص بك ليتم تشغيله بشكل أسرع - ما يصل إلى 4 مرات أسرع ، لهذا الحساب البسيط.

هل تفضل بسرعة أم دقيقة؟ - A7. تلقائي التلقائي

قد يتم تمكينه بواسطة -fassociative-math العلم في مجلس التعاون الخليجي

مزيد من القراءات

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