لماذا أرى متغيرًا مزدوجًا تمت تهيئته لبعض القيمة مثل 21.4 كـ 21.399999618530273؟

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

  •  05-07-2019
  •  | 
  •  

سؤال

double r = 11.631;
double theta = 21.4;

في مصحح الأخطاء، تظهر هذه كـ 11.631000000000000 و 21.399999618530273.

كيف يمكنني تجنب ذلك؟

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

المحلول

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

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

نصائح أخرى

أحببت شرح جويل, ، والذي يتعامل مع مشكلة دقة الفاصلة العائمة الثنائية المماثلة في Excel 2007:

هل ترى كيف يوجد الكثير من 0110 0110 0110 هناك في النهاية؟ذلك بسبب 0.1 لديه لا يوجد تمثيل دقيق في ثنائي...إنه رقم ثنائي متكرر.إنه يشبه إلى حد ما كيف أن 1/3 ليس له تمثيل في النظام العشري.1/3 هو 0.33333333 وعليك الاستمرار في كتابة 3 إلى الأبد.إذا فقدت الصبر، فستحصل على شيء غير دقيق.

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

إذا كان لديك قيمة مثل:

double theta = 21.4;

وتريد القيام به:

if (theta == 21.4)
{
}

وعليك أن تكون ذكية قليلا، وسوف تحتاج للتحقق مما إذا كانت قيمة ثيتا هي على حقا إغلاق إلى 21.4، ولكن ليس بالضرورة أن قيمة.

if (fabs(theta - 21.4) <= 1e-6)
{
}

وهذا هو جزئيا نظام أساسي محددة - ونحن لا نعرف ما منصة كنت تستخدم

.

وكما انها جزئيا حالة من معرفة ما كنت في الواقع <م> تريد لنرى. المصحح يظهر لك - إلى حد ما، على أي حال - قيمة الدقيقة المخزنة في المتغير الخاص بك. في بلدي على أرقام النقطة العائمة الثنائية في. NET ، هناك <أ href = ل "http://pobox.com/~skeet/csharp/DoubleConverter.cs" يختلط = "noreferrer"> C # الطبقة الذي يتيح لك رؤية على الإطلاق <م> بالضبط الرقم المخزن في مزدوج. النسخة الإلكترونية لا يعمل في الوقت الراهن - سأحاول أن وضع واحد حتى على موقع آخر

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

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

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

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


بالنسبة لتمثيلات العشرية الأسية، يجب حساب EPSILON لتبقى ضمن الدقة القابلة للتمثيل.بالنسبة للرقم N، إبسيلون = N / 10E+14

System.Double.Epsilon هي أصغر قيمة موجبة يمكن تمثيلها لـ Double يكتب.إنها أيضاً صغيرة لغرضنا.يقرأ نصيحة مايكروسوفت بشأن اختبار المساواة

وجئت عبر هذا من قبل ( على بلدي بلوق ) - أعتقد أن مفاجأة تميل إلى أن تكون تلك الأرقام "غير عقلانية" مختلفة

.

وبواسطة "غير منطقي" هنا أنا أشير فقط إلى حقيقة أنها لا يمكن تمثيلها بدقة في هذا الشكل. أرقام غير منطقية ريال (مثل π - بي). لا يمكن تمثيلها بدقة في جميع

ومعظم الناس هم على دراية 1/3 لا تعمل في العشرية: +0.3333333333333 ...

والشيء الغريب هو أن 1.1 لا يعمل في عوامات. يتوقع الناس القيم العشرية للعمل في أرقام النقطة العائمة بسبب الطريقة التي نفكر بها:

<اقتباس فقرة>   

1.1 هو 11 × 10 ^ -1

عند فعلا انهم في قاعدة 2

<اقتباس فقرة>   

1.1 هو 154811237190861 × 2 ^ -47

وأنت لا يمكن تجنب ذلك، عليك أن تعتاد على حقيقة أن بعض العوامات "غير منطقية"، وبنفس الطريقة التي 1/3.

وطريقة واحدة يمكنك تجنب هذا هو استخدام المكتبة التي تستخدم طريقة بديلة لتمثيل الأرقام العشرية، مثل <وأ href = "http://en.wikipedia.org/wiki/Binary_coded_decimal" يختلط = "noreferrer نوفولو "> BCD

ويبدو لي أن 21،399999618530273 هو الدقة واحد (تعويم) تمثيل 21.4. يبدو أن المصحح الصب انخفاضا من ضعف إلى تطفو في مكان ما.

إذا كنت تستخدم جافا وتحتاج دقة، استخدام فئة BigDecimal لحسابات النقطة العائمة. فمن أبطأ ولكن أكثر أمنا.

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

ولكن في معظم الوقت يمكنك ببساطة تجاهل ذلك. أن 21.4 == 21.4 يكون صحيحا لا يزال لأنه لا يزال نفس الأرقام مع نفس الخطأ. لكن 21.4f == 21.4 قد لا يكون صحيحا لأن الخطأ لتعويم وضعف مختلفة.

إذا كنت في حاجة الثابتة الدقة، ربما عليك أن تحاول أرقام نقطة ثابتة. أو حتى الصحيحة. أنا على سبيل المثال غالبا ما تستخدم كثافة (1000 * خ) لتمرير لنداء التصحيح.

إذا كان ذلك يزعج لك، يمكنك تخصيص طريقة عرض بعض القيم أثناء التصحيح. استخدامه مع الرعاية: -)

تعزيز التصحيح مع العرض المصحح سمات

تشير إلى الحساب العشري العام

خذ ملاحظة أيضًا عند مقارنة العوامات، راجع هذه الإجابة للمزيد من المعلومات.

ووفقا لجافادوك

واضاف "اذا واحد على الأقل من المعاملات إلى مشغل رقمي من نوع مزدوج، ثم
    ويتم تشغيل خارج باستخدام 64 بت الحساب الفاصلة العائمة، ونتيجة ل
    مشغل رقمي هو قيمة من النوع المزدوج. إذا المعامل الأخرى ليس ضعف، فمن
    اتسعت لأول مرة (§5.1.5) لكتابة الضعف بحلول الترويج الرقمية (§5.6) ".

هنا هو المصدر

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