تتصرف القيم العائمة بشكل مختلف عبر إصدارات الإصدار وتصحيح الأخطاء

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

سؤال

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

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

على سبيل المثال:

LEFTPOS and SPACING are defined floating point values.
float def_x;
int xpos;

def_x = LEFTPOS + (xpos * (SPACING / 2));

المشكلة تتعلق بالمترجم X360.

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

المحلول

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

نصائح أخرى

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

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

لا أعرف ما إذا كان هذا يحدث على X360 أيضًا أم لا.

لقد ساعدت أحد زملائي في العثور على مفتاح التحويل البرمجي الذي كان مختلفًا في الإصدار مقابل الإصدار.بنيات التصحيح التي كانت تسبب خلافاته.

نلقي نظرة على /fp (تحديد سلوك النقطة العائمة).

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

بالإضافة إلى أوضاع الفاصلة العائمة المختلفة التي أشار إليها الآخرون، قد يتم تشغيل SSE أو تحسينات المتجهات المماثلة للإصدار.يمكن أن يؤثر تحويل حساب الفاصلة العائمة من السجلات القياسية إلى السجلات المتجهة على البتات الأقل من نتائجك، حيث أن السجلات المتجهة ستكون بشكل عام أكثر ضيقًا (عدد بتات أقل) من سجلات الفاصلة العائمة القياسية.

ليس خطأ.وهذا النوع من الاختلاف أمر متوقع.

على سبيل المثال، تحتوي بعض الأنظمة الأساسية على سجلات عائمة تستخدم وحدات بت أكثر مما تم تخزينه في الذاكرة، لذا فإن الاحتفاظ بقيمة في السجل يمكن أن يؤدي إلى نتيجة مختلفة قليلاً مقارنة بالتخزين في الذاكرة وإعادة التحميل من الذاكرة.

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

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

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

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

إذا قمت بتعيين مفتاح التحويل البرمجي الذي يسمح للمترجم بإعادة ترتيب عمليات الفاصلة العائمة، - على سبيل المثال./fp:fast - فمن الواضح أنه ليس خطأ.

إذا لم تقم بتعيين أي مفتاح من هذا القبيل، فهذا خطأ - فمعايير C وC++ لا تسمح للمترجمين بإعادة ترتيب العمليات دون إذنك.

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