تمثيلات غير متوقعة في Python

مرحباً ، أنا أستخدم قاموسًا في بايثون لتخزين بعض المدن وسكانها على النحو التالي:

population = { 'Shanghai' : 17.8, 'Istanbul' : 13.3, 'Karachi' : 13.0, 'mumbai' : 12.5 }

الآن إذا كنت أستخدم الأمر print population ، أحصل على النتيجة:

{'Karachi': 13.0, 'Shanghai': 17.800000000000001, 'Istanbul': 13.300000000000001, 'mumbai': 12.5}

في حالة استخدام الأمر طباعة الأمر ['شنغهاي'] أحصل على الإدخال الأولي من 17.8 .

سؤالي إليك هو كيف يتم تحويل 17.8 و 13.3 إلى 17.800000000000001 و 13.300000000000001 على التوالي؟ كيف تم إنتاج كل هذه المعلومات؟ ولماذا يتم تخزينها هناك ، لأن مدخلاتي الأولية تشير إلى أنني لست بحاجة إلى هذه المعلومات الإضافية ، على الأقل بقدر ما أعرف.

3
القاموس ليس هو ما يتصرف بشكل غير متوقع بالنسبة لك. لقد قمت للتو بتشغيل Floating Point .
وأضاف المؤلف MattH, مصدر

3 إجابة

تم تغيير هذا في Python 3.1. من صفحة الجديد :

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

     

يمكن رؤية الدلالة بسهولة باستخدام رقم مثل 1.1   ليس لديك مكافئ دقيق في النقطة الثنائية العائمة. لأنه ليس هناك   لا يوجد مكافئ دقيق ، يتم تقييم تعبير مثل float ('1.1')   القيمة الأقرب التي يمكن تمثيلها وهي 0x1.199999999999ap + 0 في ست عشري   أو 1.100000000000000088817841970012523233890533447265625 بالقيمة العشرية.   هذه القيمة الأقرب كانت ولا تزال تُستخدم في النقطة العائمة اللاحقة   العمليات الحسابية.

     

الجديد هو كيفية عرض الرقم. سابقا ، تستخدم بايثون   نهج بسيط. تم حساب قيمة repr (1.1) بتنسيق (1.1 ،   '.17g') التي تم تقييمها إلى '1.1000000000000001' . ميزة   باستخدام 17 رقمًا ، تم الاعتماد على ضمانات IEEE-754 للتأكيد   أن eval (repr (1.1)) سوف تقريبًا إلى قيمتها الأصلية تمامًا.   العيب هو أن العديد من الأشخاص وجدوا أن الإخراج مربكًا   (الخطأ في تحديد القيود الجوهرية للنقطة العائمة الثنائية   التمثيل باعتباره مشكلة مع بيثون نفسها).

     

تعد الخوارزمية الجديدة لـ repr (1.1) أكثر ذكاءً وتعيد '1.1' .   على نحو فعال ، فإنه يبحث في جميع تمثيل سلسلة مكافئة (تلك   التي يتم تخزينها باستخدام نفس القيمة العائمة الأساسية) وترجع   أقصر تمثيل.

     

تميل الخوارزمية الجديدة إلى إصدار تمثيلات أنظف قدر الإمكان ،   لكنه لا يغير القيم الأساسية. لذلك ، لا يزال الأمر كذلك   هذا 1.1 + 2.2! = 3.3 على الرغم من أن التوضيحات قد تقترح   على خلاف ذلك.

     

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

     

(يساهم بها Eric Smith و Mark Dickinson ؛ العدد 1580 )

4
وأضاف

تحتاج إلى قراءة كيفية عمل أرقام الفاصلة العائمة في أجهزة الكمبيوتر.

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

ربما يرجع ذلك إلى اختلافات في منطق الطباعة المستخدم في حالتين الاستخدام التي تصفهما. لم أستطع إعادة إنتاج السلوك (باستخدام Python 2.7.2 في Win64).

إذا كنت تستخدم رقمًا يمكن تمثيله تمامًا ، مثل 1.5 ، فإنني أعتقد أن هذا التأثير سيختفي.

2
وأضاف
شكرا لك على المعلومات. أعتقد أن الأرقام العائمة يجب أن تكون هي الحالة. سأترك هذه الإجابة مفتوحة لمعرفة ما إذا كان أي شخص آخر سيضيف شيئاً ، لفترة من الوقت ، وإذا لم يكن كذلك ، سأقوم بإغلاقه. شكرًا لك مرة أخرى.
وأضاف المؤلف NlightNFotis, مصدر
لا شيء يضيف ، الاسترخاء هو الصحيح على كلا النقطتين. عند "طباعة" dict ، تحصل على التمثيل الداخلي لقيم float ، بينما عند طباعة قيمة float تحصل على الإصدار "stringyfied" (مستدير). جرب "طباعة repr (السكان [" shangai "])" و "str str (السكان [" shangai "])" ...
وأضاف المؤلف bruno desthuilliers, مصدر

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

See the Python manual for information: http://docs.python.org/library/decimal.html

>>> from decimal import Decimal
>>> print Decimal('3.14')
3.14
1
وأضاف
ما عدا الاعتناء - العشرية s لا تزال أرقام الفاصلة العائمة ، فقط مع الأساس 10 بدلاً من الأساسي 2.
وأضاف المؤلف Katriel, مصدر