سؤال

كان لدي لحظة WTF صغيرة هذا الصباح. يمكن تلخيص WTF مع هذا:

float x = 0.2f;
float y = 0.1f;
float z = x + y;
assert(z == x + y); //This assert is triggered! (Atleast with visual studio 2008)

يبدو أن السبب هو أن التعبير x + y يتم الترويج لمضاعفة ومقارنة مع النسخة المقتطعة في z. وبعد (إذا غيرت z ل double هذا التأمل لا يتم تشغيله).

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

4.6.1."rvalue من النوع float يمكن تحويلها إلى rvalue من النوع double. وبعد القيمة لم تتغير "

سؤالي هو، هو x + y مضمونة للترويج لمضاعفة أو في تقدير المترجم؟

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

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

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

المحلول

لا يمكنك أن تفترض ذلك بشكل عام == سوف تعمل كما هو متوقع لأنواع النقطة العائمة. قارن بين القيم الدائرية أو استخدامها تشبه abs(a-b) < tolerance في حين أن.

الترويج بالكامل وفقا لتقدير مترجم (وسيعتمد على الأجهزة المستهدفة ومستوى التحسين وما إلى ذلك).

ما يجري في هذه الحالة بالذات هو بالتأكيد أن القيم يتم تخزينها في سجلات FPU بدقة أعلى من الذاكرة - بشكل عام، يعمل أجهزة FPU الحديثة مع دقة مزدوجة أو أعلى داخليا مهما كان الدقة التي طلبها مبرمج، مع رمز إنشاء الترجمة لجعل التحويلات المناسبة عند تخزين القيم بالذاكرة؛ في بناء غير مخطط لها، نتيجة x+y لا يزال في سجل عند نقطة المقارنة ولكن z سيتم تخزينها إلى الذاكرة وظهرت مرة أخرى، وبالتالي اقتطاعها بدقة تعويم.

نصائح أخرى

ال مشروع عمل للمعيار التالي C ++ 0x القسم 5 نقاط 11 يقول

قد يتم تمثيل قيم المعاملات العائمة ونتائج التعبيرات العائمة بدقة أكبر وتتراوح من ذلك المطلوب من النوع؛ لا تتغير الأنواع وبالتالي

لذلك في تقدير مترجم.

باستخدام GCC 4.3.2، والتأكيد هو ليس الناجمة، وبالفعل، عاد rvalue من x + y هو float, ، بدلا من double.

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

الأسئلة الشائعة C ++ Lite لديها بعض مناقشة أخرى حول هذا الموضوع:

إنها المشكلة منذ عدد تعويم التحويل الثنائي لا يعطي دقة دقيقة.

وداخل sizeof(float) بايت من أنه غير قادر على استيعاب القيمة الدقيقة للعدد العائم والتشغيل الحسابي يؤدي إلى تقريب وفشل المساواة.

انظر أدناه على سبيل المثال

float x = 0.25f; //both fits within 4 bytes with precision
float y = 0.50f;
float z = x + y;
assert(z == x + y); // it would work fine and no assert

أعتقد أنه سيكون في تقدير المترجم، ولكن يمكنك دائما إجباره على ما إذا كان ذلك كان تفكيرك؟

سبب آخر لن مقارنة العوامات مباشرة أبدا.

if (fabs(result - expectedResult) < 0.00001)
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top