بايثون إنفينيتي - أي محاذير؟
سؤال
إذن لدى بايثون لانهاية موجبة وسالبة:
float("inf"), float("-inf")
يبدو أن هذا هو نوع الميزة التي يجب أن تحتوي على بعض التحذيرات.هل هناك أي شيء يجب أن أكون على علم به؟
المحلول
ويمكنك الحصول على ما زالت لا واحد في عدد (نان) القيم من حسابية بسيطة تنطوي inf
:
>>> 0 * float("inf")
nan
وتجدر الإشارة إلى أنك سوف عادة <م> لا م> الحصول على قيمة inf
من خلال العمليات الحسابية المعتادة:
>>> 2.0**2
4.0
>>> _**2
16.0
>>> _**2
256.0
>>> _**2
65536.0
>>> _**2
4294967296.0
>>> _**2
1.8446744073709552e+19
>>> _**2
3.4028236692093846e+38
>>> _**2
1.157920892373162e+77
>>> _**2
1.3407807929942597e+154
>>> _**2
Traceback (most recent call last):
File "<stdin>", line 1, in ?
OverflowError: (34, 'Numerical result out of range')
وتعتبر قيمة inf
قيمة خاصة جدا مع دلالات غير عادية، لذلك فمن الأفضل أن تعرف حول OverflowError
على الفور من خلال استثناء، بدلا من وجود قيمة inf
حقن بصمت في الحسابات الخاصة بك.
نصائح أخرى
تنفيذ بايثون يتبع معيار IEEE-754 جيد جدًا، والذي يمكنك استخدامه كدليل، ولكنه يعتمد على النظام الأساسي الذي تم تجميعه عليه، لذا اختلافات المنصة قد يحدث.مؤخرًا¹، تم تطبيق إصلاح يسمح بذلك "اللانهاية" وكذلك "inf", ، ولكن هذا له أهمية ثانوية هنا.
تنطبق الأقسام التالية بشكل متساوٍ على أي لغة تنفذ حساب النقطة العائمة لـ IEEE بشكل صحيح، وهي لا تقتصر على لغة Python فقط.
مقارنة لعدم المساواة
عند التعامل مع اللانهاية وأكبر من >
أو أقل من <
المشغلين، التهم التالية:
- أي رقم بما في ذلك
+inf
أعلى من-inf
- أي رقم بما في ذلك
-inf
أقل من+inf
+inf
يكون لا أعلى ولا أقل من+inf
-inf
ليس أعلى ولا أقل من-inf
- أي مقارنة تنطوي على
NaN
هو زائف (inf
ليس أعلى ولا أقل منNaN
)
المقارنة من أجل المساواة
عند المقارنة من أجل المساواة، +inf
و +inf
متساوون، كما هي -inf
و -inf
.هذه قضية محل جدل كبير وقد تبدو مثيرة للجدل بالنسبة لك، لكنها تتوافق مع معيار IEEE وتتصرف بايثون بهذه الطريقة.
بالطبع، +inf
غير متكافئ ل -inf
وكل شيء، بما في ذلك NaN
في حد ذاته، لا يساوي NaN
.
الحسابات مع اللانهاية
معظم العمليات الحسابية مع اللانهاية سوف تسفر عن ما لا نهاية، ما لم يكن كلا المعاملين لا نهاية، عند قسمة العملية أو المعامل، أو مع الضرب بصفر، هناك بعض القواعد الخاصة التي يجب وضعها في الاعتبار:
- عند ضربه بصفر، والنتيجة غير محددة، فإنه ينتج
NaN
- عند قسمة أي رقم (ما عدا اللانهاية نفسها) على اللانهاية، الذي ينتج
0.0
أو-0.0
². - عند قسمة (بما في ذلك المعامل) اللانهاية الإيجابية أو السلبية على اللانهاية الإيجابية أو السلبية، تكون النتيجة غير محددة، لذلك
NaN
. - عند الطرح قد تكون النتائج مفاجئة، لكن تابع الحس الرياضي المشترك:
- عند القيام
inf - inf
, ، النتيجة غير محددة:NaN
; - عند القيام
inf - -inf
, ، النتيجه هيinf
; - عند القيام
-inf - inf
, ، النتيجه هي-inf
; - عند القيام
-inf - -inf
, ، النتيجة غير محددة:NaN
.
- عند القيام
- عند الإضافة، قد يكون الأمر مفاجئًا أيضًا:
- عند القيام
inf + inf
, ، النتيجه هيinf
; - عند القيام
inf + -inf
, ، النتيجة غير محددة:NaN
; - عند القيام
-inf + inf
, ، النتيجة غير محددة:NaN
; - عند القيام
-inf + -inf
, ، النتيجه هي-inf
.
- عند القيام
- استخدام
math.pow
,pow
أو**
أمر صعب، لأنه لا يتصرف كما ينبغي.فإنه يطرح استثناء تجاوز السعة عندما تكون النتيجة ذات رقمين حقيقيين عالية جدًا بحيث لا تتناسب مع تعويم مزدوج الدقة (يجب أن ترجع اللانهاية)، ولكن عندما يكون الإدخالinf
أو-inf
, فإنه يتصرف بشكل صحيح ويعود أيضًاinf
أو0.0
.عندما تكون الحجة الثانيةNaN
, ، يعودNaN
, ، ما لم تكن الوسيطة الأولى كذلك1.0
.هناك المزيد من القضايا، وليس كلها مغطاة في المستندات. math.exp
يعاني من نفس المشاكلmath.pow
.الحل لإصلاح هذا التجاوز هو استخدام تعليمات برمجية مشابهة لما يلي:try: res = math.exp(420000) except OverflowError: res = float('inf')
ملحوظات
ملاحظة 1: كتحذير إضافي، كما هو محدد في معيار IEEE، إذا كانت النتيجة الحسابية الخاصة بك أقل من أو تجاوزت السعة، فلن تكون النتيجة خطأ أقل من أو تجاوز السعة، ولكن لا نهاية إيجابية أو سلبية: 1e308 * 10.0
عائدات inf
.
ملاحظة 2: لأن أي حساب مع NaN
عائدات NaN
وأي مقارنة ل NaN
, ، مشتمل NaN
في حد ذاته false
, ، يجب عليك استخدام math.isnan
وظيفة لتحديد ما إذا كان الرقم هو في الواقع NaN
.
ملاحظة 3: على الرغم من أن بايثون تدعم الكتابة float('-NaN')
, ، تم تجاهل العلامة، لأنه لا يوجد أي تسجيل دخول NaN
داخليا.إذا قسمت -inf / +inf
, ، النتيجه هي NaN
, ، لا -NaN
(لا يوجد شيء من هذا القبيل).
ملاحظة 4: كن حذرًا في الاعتماد على أي مما سبق، حيث تعتمد بايثون على مكتبة C أو Java التي تم تجميعها لها ولا تنفذ جميع الأنظمة الأساسية كل هذا السلوك بشكل صحيح.إذا كنت تريد التأكد، فاختبر اللانهاية قبل إجراء حساباتك.
¹) مؤخرا يعني منذ ذلك الحين الإصدار 3.2.
²) تدعم النقاط العائمة الصفر الموجب والسالب، لذا: x / float('inf')
يحتفظ بعلامته و -1 / float('inf')
عائدات -0.0
, 1 / float(-inf)
عائدات -0.0
, 1 / float('inf')
عائدات 0.0
و -1/ float(-inf)
عائدات 0.0
.فضلاً عن ذلك، 0.0 == -0.0
يكون true
, ، يجب عليك التحقق يدويًا من الإشارة إذا كنت لا تريد أن تكون صحيحة.
C99 .
وتمثيل نقطة IEEE 754 عائمة تستخدم من قبل جميع المعالجات الحديثة لديها العديد من أنماط قليلا خاص محفوظة لاللانهاية الإيجابية (علامة = 0، إكسب = ~ 0 فارك = 0)، سلبي لا نهاية (علامة = 1، إكسب = ~ 0، فارك = 0)، والعديد من نان (ليس رقم: إكسب = ~ 0 فارك ≠ 0)
.وكل ما عليك ما يدعو للقلق: قد يسبب بعض العمليات الحسابية العائمة الاستثناءات نقطة / الفخاخ، ولكن تلك ليست تقتصر على هذه الثوابت "مثيرة للاهتمام"
ولقد وجدت التحذير من أن أحدا لم يذكر حتى الآن. أنا لا أعرف ما إذا كان سوف يأتي في كثير من الأحيان في حالات عملية، ولكن هنا هو من أجل اكتمالها.
وعادة، وحساب اللانهاية عدد مودولو يعود نفسه على تعويم، ولكن جزء مودولو عوائد اللانهاية nan
(وليس رقم). هنا مثال:
>>> from fractions import Fraction
>>> from math import inf
>>> 3 % inf
3.0
>>> 3.5 % inf
3.5
>>> Fraction('1/3') % inf
nan
وأنا رفعت قضية على بيثون تعقب علة. يمكن أن ينظر إليه على https://bugs.python.org/issue32968 .
تحديث: سيكون هذا الثابتة في بيثون 3.8