Python Infinity - คำเตือนใด ๆ


179

Python มีค่าเป็นบวกและลบ:

float("inf"), float("-inf")

นี่ดูเหมือนจะเป็นคุณลักษณะประเภทที่ต้องมีข้อแม้บางอย่าง มีอะไรบ้างที่ฉันควรระวัง?


25
โปรดทราบว่าคง1e309จะถูกตีความว่าเป็น+infและจะถูกตีความว่าเป็น-1e309 -inf
Chris Taylor

คำตอบ:


97

คุณยังสามารถรับค่าที่ไม่เป็นตัวเลข (NaN) ได้จากการคำนวณทางคณิตศาสตร์อย่างง่ายที่เกี่ยวข้อง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ค่าฉีดอย่างเงียบ ๆ ในการคำนวณของคุณ


8
การเพิ่มโฟลตแบบง่ายการคูณและอื่น ๆ จะสร้าง inf อย่างมีความสุขแม้ว่า: f = 1.3407807929942597e + 154; f * f => inf ดูเหมือนว่าเป็นข้อยกเว้นของ ** ที่จะยกระดับ OverflowError
eregon

@eregon ที่จริงแล้ว**ดูเหมือนว่ารถเข็นเด็กเล็ก เมื่อมันล้นกับตัวเลขจริงมันจะพ่นข้อผิดพลาด แต่เมื่อถูกดำเนินการใด ๆ ที่เป็นinfหรือ-infจะส่งกลับอย่างใดอย่างหนึ่งหรือ0.0 infดังนั้นจึงไม่ทำงานอย่างถูกต้องเมื่อเข้าเป็น inifinty แต่ไม่เมื่อผลที่ควรจะเป็นอินฟินิตี้
Abel

2
@bel นั่นไม่ใช่รถม้า ล้นหมายถึงจำนวนที่มีขนาดใหญ่มาก ที่มีขนาดใหญ่เกินกว่าที่จะเป็นตัวแทนของมัน แต่ยังคงห่างไกลมีขนาดเล็กกว่าอินฟินิตี้ การวางอินฟินิตี้ในสถานที่ดังกล่าวอาจมีประโยชน์สำหรับตัวจัดการข้อยกเว้นของตรรกะแอปพลิเคชันของคุณโดยเฉพาะ แต่จะไม่ถูกต้องสำหรับ Python โดยทั่วไป
Lutz Prechelt

6
@ Lutz ถ้ามันเกิดขึ้นจากการคูณมันก็ยังคงเป็นพฤติกรรมที่ไม่สอดคล้องกัน แน่นอนว่า * ใหญ่ก็ไม่ได้ไม่มีที่สิ้นสุดเช่นกัน
Richard Rast

100

การใช้งานของ Python นั้นเป็นไปตามมาตรฐาน IEEE-754ค่อนข้างดีซึ่งคุณสามารถใช้เป็นแนวทาง แต่ขึ้นอยู่กับระบบพื้นฐานที่รวบรวมไว้ดังนั้นอาจมีความแตกต่างของแพลตฟอร์ม เมื่อเร็ว ๆ นี้มีการใช้การแก้ไขที่อนุญาตให้"อนันต์" และ "inf"แต่มีความสำคัญเล็กน้อยที่นี่

ส่วนต่อไปนี้ใช้ได้ดีกับภาษาใด ๆ ที่ใช้การคำนวณเลขทศนิยมของ IEEE อย่างถูกต้องไม่เฉพาะเจาะจงกับ Python เท่านั้น

เปรียบเทียบความไม่เท่าเทียม

เมื่อจัดการกับอินฟินิตี้และตัวดำเนินการมากกว่า>หรือน้อยกว่า<ค่าต่อไปนี้จะนับ:

  • หมายเลขใด ๆ รวมถึง +infสูงกว่า-inf
  • หมายเลขใด ๆ รวมถึง-infต่ำกว่า+inf
  • +infเป็นค่าที่สูงขึ้นหรือลดลงกว่า+inf
  • -inf ไม่สูงหรือต่ำกว่า -inf
  • การเปรียบเทียบใด ๆ ที่เกี่ยวข้องNaNเป็นเท็จ ( infไม่สูงกว่าหรือต่ำกว่าNaN)

เปรียบเทียบเพื่อความเท่าเทียมกัน

เมื่อเปรียบเทียบความเสมอภาค+infและ+infเท่าเทียมกันเช่นเดียวกับและ-inf -infนี่เป็นปัญหาที่ถกเถียงกันมากและอาจฟังดูขัดแย้งกับคุณ แต่มันอยู่ในมาตรฐาน IEEE และ Python ทำงานแบบนั้น

แน่นอน+infคือไม่เท่ากันไป-infและทุกอย่างรวมถึงตัวเองเป็นไม่เท่ากันไปNaNNaN

การคำนวณด้วยอนันต์

การคำนวณส่วนใหญ่ที่มีอนันต์จะให้ผลอนันต์ยกเว้นว่าตัวถูกดำเนินการทั้งสองนั้นเป็นอนันต์เมื่อการหารการดำเนินงานหรือโมดูโลหรือการคูณด้วยศูนย์มีกฎพิเศษบางอย่างที่ต้องจำไว้:

  • เมื่อคูณด้วยศูนย์ซึ่งผลลัพธ์ไม่ได้ถูกกำหนดจะให้ผลลัพธ์ NaN
  • เมื่อหารจำนวนใด ๆ (ยกเว้นอนันต์เอง) ด้วยอนันต์ซึ่งให้ผล0.0หรือ-0.0²
  • เมื่อหาร (รวมทั้งแบบโมดูโล) NaNบวกหรือเชิงลบโดยอินฟินิตี้อินฟินิตี้บวกหรือลบผลที่ได้คือไม่ได้กำหนดดังนั้น
  • เมื่อทำการลบผลลัพธ์อาจน่าแปลกใจ แต่เป็นไปตามความรู้สึกทางคณิตศาสตร์ทั่วไป :
    • เมื่อทำinf - infผลลัพธ์จะไม่ได้กำหนด:NaN ;
    • เมื่อทำinf - -infผลที่ได้คือinf ;
    • เมื่อทำ-inf - infผลที่ได้คือ-inf ;
    • เมื่อทำผลที่ได้คือไม่ได้กำหนด:-inf - -infNaN
  • เมื่อเพิ่มมันอาจเป็นเรื่องที่น่าแปลกใจเช่นกัน:
    • เมื่อทำ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.expmath.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:แม้ว่า Python รองรับการเขียนfloat('-NaN')แต่สัญญาณจะถูกละเว้นเนื่องจากไม่มีการลงชื่อเข้าใช้NaNภายใน หากคุณแบ่ง-inf / +infผลที่ได้คือNaNไม่-NaN (ไม่มีสิ่งนั้น)

หมายเหตุ 4:ใช้ความระมัดระวังอย่างใดอย่างหนึ่งดังกล่าวข้างต้นเนื่องจาก Python อาศัยไลบรารี 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คุณต้องตรวจสอบเครื่องหมายด้วยตนเองหากคุณไม่ต้องการให้เป็นจริง


11
nitpick ขนาดเล็ก: ไม่ใช่ทุกการคำนวณที่มีอนันต์ให้ผลอนันต์:-1 * float('infinity') == -inf
Evan Krall

4
นั่นเป็นเหตุผลที่ฉันพูดว่ามันเป็นnitpick ขนาดเล็ก คุณทำให้ฉันกังวลสักครู่หนึ่งว่าเครื่องหมายจะถูกละเว้นโดยสิ้นเชิงเมื่อทำงานกับอินฟินิตี้และฉันต้องการชี้แจงให้คนอื่นฟัง
Evan Krall

12
เกือบ: 1 / float ('infinity') == 0.0
Phil

3
@ ฟิล: ถึงแม้ว่าฉันค่อนข้างแน่ใจว่าคุณกำลังพยายามแสดงให้เห็นว่าไม่ใช่การคำนวณทั้งหมดที่มีผลทำให้ inf เป็น inf หรือ NaN แต่ฉันแค่ต้องการทำให้ชัดเจนต่อผู้อื่นที่อาจอ่านความคิดเห็นนั่น 1 / ลอยตัว (ไม่มีที่สิ้นสุด) ') == 0.0 เป็นจริง สำหรับในขณะที่คุณกำลังเข้าใกล้อนันต์ผลลัพธ์ของการแบ่งเข้าใกล้ 0 ฉันรู้ว่ามันเป็นแคลคูลัสพื้นฐาน แต่ฉันต้องการให้แน่ใจว่าผู้อ่านเข้าใจหรืออย่างน้อยก็มีเงื่อนงำว่าทำไมผลลัพธ์คืออะไร
Anthony Pace

1
ฉันรู้สึกว่าคำตอบนี้ดีกว่าคำตอบที่ยอมรับ
Christian Herenz

3

C99ก็เช่นกัน C99

การแทนค่าจุดลอยตัว IEEE 754 ที่ใช้โดยตัวประมวลผลที่ทันสมัยทั้งหมดมีหลายรูปแบบบิตพิเศษที่สงวนไว้สำหรับอินฟินิตี้บวก (เครื่องหมาย = 0, exp = ~ 0, frac = 0), อินฟินิตี้ลบ (เครื่องหมาย = 1, exp = ~ 0, frac = 0 ) และ NaN จำนวนมาก (ไม่ใช่ตัวเลข: exp = ~ 0, frac ≠ 0)

สิ่งที่คุณต้องกังวลเกี่ยวกับ: เลขคณิตบางอย่างอาจทำให้เกิดข้อยกเว้น / กับดักของจุดลอยตัว แต่สิ่งเหล่านั้นไม่ได้ จำกัด อยู่เพียงค่าคงที่ "น่าสนใจ" เท่านั้น


1
ดังนั้นถ้าเลขคณิตของฉันใหญ่เกินไปมันอาจกลายเป็น inf?
Casebash

@Casebash OverflowErrorไม่มีก็จะทำให้เกิดการ
wizzwizz4

2

ฉันพบข้อแม้ที่ไม่มีใครพูดถึง ฉันไม่รู้ว่ามันจะเกิดขึ้นบ่อยครั้งในสถานการณ์จริงหรือไม่ แต่นี่ก็เพื่อความสมบูรณ์แบบ

โดยปกติแล้วการคำนวณตัวเลขแบบโมดูโลอินฟินิตี้จะคืนค่าตัวเองเป็นแบบลอยตัว แต่เศษส่วนแบบโมดูโลแบบอินฟินิตี้จะส่งกลับnan(ไม่ใช่ตัวเลข) นี่คือตัวอย่าง:

>>> from fractions import Fraction
>>> from math import inf
>>> 3 % inf
3.0
>>> 3.5 % inf
3.5
>>> Fraction('1/3') % inf
nan

ฉันได้ยื่นปัญหาในตัวติดตามข้อผิดพลาดของ Python สามารถดูได้ที่https://bugs.python.org/issue32968 https://bugs.python.org/issue32968

ปรับปรุง: นี้จะถูกแก้ไขใน Python 3.8


2

ถ้ำที่ไม่ดีมาก: หารด้วยศูนย์

เป็น1/xเศษเล็กเศษน้อยขึ้นอยู่กับx = 1e-323ว่ามันเป็นinfแต่เมื่อx = 1e-324หรือน้อยมันจะพ่นZeroDivisionError

>>> 1/1e-323
inf

>>> 1/1e-324
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: float division by zero

ดังนั้นต้องระวัง!

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.