كيف C# تقييم النقطة العائمة في تحوم فوق المتوسطة نافذة مقابل تجميع?

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

  •  05-07-2019
  •  | 
  •  

سؤال

أنا أرى شيء غريب مع تخزين الزوجي في القاموس ، وأنا في حيرة لماذا.

هنا كود:

            Dictionary<string, double> a = new Dictionary<string, double>();
            a.Add("a", 1e-3);

            if (1.0 < a["a"] * 1e3)
                Console.WriteLine("Wrong");

            if (1.0 < 1e-3 * 1e3)
                Console.WriteLine("Wrong");

الثانية إذا كان البيان يعمل كما هو متوقع ، 1.0 ليس أقل من 1.0.الآن, الأول كان يقيم صحيح.جدا الشيء الغريب هو أنه عندما كنت تحوم فوق إذا intellisense يقول لي كاذبة ، بعد رمز لحسن الحظ ينتقل إلى وحدة التحكم.WriteLine.

هذا هو C# 3.5 في Visual Studio 2008.

هل هذه النقطة العائمة دقة المشكلة ؟ ثم لماذا الثانية إذا كان البيان العمل ؟ أشعر أنا في عداد المفقودين شيء أساسي جدا هنا.

أي فكرة هو موضع تقدير.

Edit2 (إعادة تحديد الأهداف السؤال قليلا):

أنا لا يمكن أن يقبل الرياضيات الدقة المشكلة ، ولكن سؤالي الآن هو:لماذا تحوم فوق تقييم بشكل صحيح ؟ وهذا أيضا ينطبق المتوسطة النافذة.أنا لصق رمز من الأولى إذا كان البيان في المتوسطة نافذة ويقيم كاذبة.

التحديث

أولا شكرا جزيلا على كل الإجابات.

أنا أيضا وجود مشاكل إعادة هذا في مشروع آخر على نفس الجهاز.تبحث في إعدادات المشروع ، لا أرى أي اختلافات.تبحث في IL بين المشاريع أرى أي فرق.تبحث في التفكيك ، لا أرى أي اختلافات واضحة (إلى جانب عناوين الذاكرة).ولكن عندما كنت التصحيح المشروع الأصلي ، أرى:screenshot of problem

الإطار الحالي يقول لي إذا كان غير صحيح ، لكن هذا القانون يندرج في المشروط.

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

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

المحلول

فمن العائمة الدقة المشكلة.

البيان الثاني يعمل لأن المترجم التهم التعبير 1e-3 * 1e3 قبل ينبعث منها .exe.

ابحث عنه في ILDasm/عاكس, وسوف تنبعث منها شيئا مثل

 if (1.0 < 1.0)
                Console.WriteLine("Wrong");

نصائح أخرى

المشكلة هنا هو دقيق جدا.C# compiler لا (دائما) تنبعث من التعليمات البرمجية التي لا حساب في ضعف ، حتى عندما يكون هذا النوع الذي قمت بتحديده.ولا سيما أنها تنبعث من التعليمات البرمجية التي لا حساب في "الموسعة" الدقة باستخدام x87 تعليمات دون التقريب نتائج المتوسطة إلى مضاعفة.

اعتمادا على ما إذا كان 1e-3 تقييم مزدوج أو مزدوجة طويلة ، وما إذا كان الضرب هو محسوب في ضعف أو مزدوجة طويلة, فمن الممكن الحصول على أي من التالية ثلاث نتائج:

  • (مزدوجة طويلة)1e-3 * 1e3 حسابها في مزدوجة طويلة هو 1.0 - ابسيلون
  • (مزدوج)1e-3 * 1e3 حسابها في مضاعفة بالضبط 1.0
  • (مزدوج)1e-3 * 1e3 حسابها في مزدوجة طويلة 1.0 + ابسيلون

ومن الواضح المقارنة الأولى التي تخفق في تلبية التوقعات الخاصة بك ويجري تقييم بالطريقة الموضحة في السيناريو الثالث أنا المذكورة.1e-3 يتم تقريب إلى ضعف إما لأنه يتم تخزينها وتحميلها مرة أخرى ، الأمر الذي يفرض على التقريب ، أو بسبب C# تسلم 1e-3 كما الدقة مزدوج الحرفي يعامل بهذه الطريقة.الضرب يجري تقييمها في مزدوجة طويلة بسبب C# لديها دماغيا العددية نموذج هكذا المترجم هو توليد التعليمات البرمجية.

الضرب في المقارنة الثانية إما يجري تقييمها باستخدام إحدى الطريقتين ، (يمكنك معرفة أي من خلال محاولة "1 > 1e-3 * 1e3") ، أو المترجم هو التقريب نتيجة الضرب قبل مقارنة مع 1.0 عندما يقيم التعبير في وقت الترجمة.

فمن المرجح الممكن بالنسبة لك أن تقول مترجم عدم استخدام الموسعة الدقة دون أن يقول ذلك عبر بعض بناء الإعداد ؛ تمكين codegen إلى SSE2 قد تعمل أيضا.

انظر الأجوبة هنا

أم...غريبة.أنا لست قادرا على إعادة إنتاج المشكلة.أنا باستخدام C# 3.5 و Visual Studio 2008 أيضا.كنت قد كتبته في المثال الخاص بك بالضبط كما تم نشر و أنا لا أرى أي Console.WriteLine بيان تنفيذ.

أيضا, الثاني إذا كان البيان هو الحصول الأمثل من قبل المترجم.عندما فحص التصحيح وإصدار يبني في ILDASM/عاكس أرى أي دليل على ذلك.التي تجعل منذ لأنني الحصول على مترجم تحذير رمز تصل تم الكشف على ذلك.

أخيرا, أنا لا أرى كيف يمكن أن تكون هذه النقطة العائمة الدقة المسألة على أية حال.لماذا المحول البرمجي C# ثابت تقييم اثنين الزوجي بشكل مختلف عن CLR في وقت التشغيل?اذا كان هذا الحال ثم أحد يستطيع ان ينكر C# compiler له علة.

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

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