Python Infinity - Ada peringatan?

179

Jadi Python memiliki infinity positif dan negatif:

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

Ini sepertinya jenis fitur yang harus memiliki beberapa peringatan. Apakah ada sesuatu yang harus saya waspadai?

Casebash
sumber
25
Perhatikan bahwa konstanta 1e309akan ditafsirkan sebagai +infdan -1e309akan ditafsirkan sebagai -inf.
Chris Taylor

Jawaban:

97

Anda masih bisa mendapatkan nilai bukan angka (NaN) dari aritmatika sederhana yang melibatkan inf:

>>> 0 * float("inf")
nan

Perhatikan bahwa Anda biasanya tidak akan mendapatkan infnilai melalui perhitungan aritmatika biasa:

>>> 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')

The infnilai dianggap sebagai nilai yang sangat khusus dengan semantik yang tidak biasa, jadi lebih baik untuk mengetahui tentang OverflowErrorlangsung melalui pengecualian, daripada memiliki infnilai diam-diam disuntikkan ke dalam perhitungan Anda.

Greg Hewgill
sumber
8
Tambahan float sederhana, multiplikasi, dll akan dengan senang hati menghasilkan inf meskipun: f = 1.3407807929942597e + 154; f * f => inf. Tampaknya agak pengecualian ** untuk meningkatkan OverflowError.
eregon
@ eregon, sebenarnya, **tampak agak buggy. Ketika meluap dengan angka nyata, ia melempar kesalahan, tetapi ketika salah satu operandnya adalah infatau -inf, ia mengembalikan salah satu 0.0atau inf. Jadi tidak bekerja dengan benar ketika input inifinty, tetapi tidak ketika hasilnya harus tak terhingga.
Abel
2
@ Bel Itu bukan buggy. Melimpah berarti jumlahnya sangat besar. Terlalu besar untuk diwakili, tetapi masih jauh lebih kecil dari tak terbatas. Menempatkan infinity ke tempat seperti itu mungkin berguna untuk pengendali pengecualian logika aplikasi khusus Anda, tetapi akan salah untuk Python secara umum.
Lutz Prechelt
6
@ Lutz jika muncul sebagai perkalian maka, itu masih perilaku yang tidak konsisten. Besar * besar juga bukan tanpa batas.
Richard Rast
100

Implementasi Python mengikuti standar IEEE-754 dengan cukup baik, yang dapat Anda gunakan sebagai panduan, tetapi ia bergantung pada sistem yang mendasari kompilasi, sehingga perbedaan platform dapat terjadi. Baru-baru ini¹, perbaikan telah diterapkan yang memungkinkan "infinity" serta "inf" , tetapi itu tidak penting di sini.

Bagian berikut ini sama-sama berlaku untuk bahasa apa pun yang menerapkan aritmatika titik apung IEEE dengan benar, tidak khusus hanya untuk Python.

Perbandingan untuk ketimpangan

Ketika berhadapan dengan operator tanpa batas dan operator lebih besar daripada >atau lebih kecil <, berikut ini diperhitungkan:

  • angka berapa pun termasuk +inflebih tinggi dari-inf
  • nomor berapa pun termasuk -inflebih rendah dari+inf
  • +infyang tidak lebih tinggi atau lebih rendah dari+inf
  • -inf tidak lebih tinggi atau lebih rendah dari -inf
  • setiap perbandingan yang terlibat NaNsalah ( inftidak lebih tinggi, atau lebih rendah dari NaN)

Perbandingan untuk kesetaraan

Jika dibandingkan untuk kesetaraan, +inf dan +infsama, seperti apa adanya -infdan -inf. Ini adalah masalah yang banyak diperdebatkan dan mungkin terdengar kontroversial bagi Anda, tetapi itu dalam standar IEEE dan Python berperilaku seperti itu.

Tentu saja, +inf tidak sama dengan -infdan segala sesuatu, termasuk NaNdirinya sendiri, tidak sama dengan NaN.

Perhitungan dengan tak terhingga

Sebagian besar perhitungan dengan tak terhingga akan menghasilkan tak terhingga, kecuali kedua operan adalah tak terhingga, ketika divisi operasi atau modulo, atau dengan perkalian dengan nol, ada beberapa aturan khusus yang perlu diingat:

  • ketika dikalikan dengan nol, yang hasilnya tidak ditentukan, hasilnya NaN
  • ketika membagi angka apa pun (kecuali tak terhingga itu sendiri) dengan tak terhingga, yang menghasilkan 0.0atau -0.0².
  • ketika membagi (termasuk modulo) infinity positif atau negatif dengan infinity positif atau negatif, hasilnya tidak terdefinisi, jadi NaN.
  • saat mengurangi, hasilnya mungkin mengejutkan, tetapi ikuti akal sehat matematika :
    • ketika melakukan inf - inf, hasilnya tidak terdefinisi: NaN;
    • ketika melakukan inf - -inf, hasilnya adalah inf;
    • ketika melakukan -inf - inf, hasilnya adalah -inf;
    • ketika melakukan -inf - -inf, hasilnya tidak terdefinisi: NaN.
  • saat menambahkan, ini juga bisa mengejutkan:
    • ketika melakukan inf + inf, hasilnya adalah inf;
    • ketika melakukan inf + -inf, hasilnya tidak terdefinisi: NaN;
    • ketika melakukan -inf + inf, hasilnya tidak terdefinisi: NaN;
    • ketika melakukan -inf + -inf, hasilnya adalah -inf.
  • menggunakan math.pow, powatau **rumit, karena tidak berperilaku sebagaimana mestinya. Itu melempar pengecualian melimpah ketika hasil dengan dua bilangan real terlalu tinggi untuk muat pelampung presisi ganda (harus mengembalikan tak terhingga), tetapi ketika inputnya infatau -inf, itu berperilaku benar dan mengembalikan salah satu infatau 0.0. Ketika argumen kedua adalah NaN, ia kembali NaN, kecuali argumen pertama adalah 1.0. Ada lebih banyak masalah, tidak semua dibahas dalam dokumen .
  • math.expmenderita masalah yang sama dengan math.pow. Solusi untuk memperbaiki ini untuk overflow adalah dengan menggunakan kode yang mirip dengan ini:

    try:
        res = math.exp(420000)
    except OverflowError:
        res = float('inf')

Catatan

Catatan 1: sebagai peringatan tambahan, yang seperti yang didefinisikan oleh standar IEEE, jika hasil perhitungan Anda di bawah atau melebihi, hasilnya tidak akan menjadi kesalahan di bawah atau overflow, tetapi tak terhingga positif atau negatif: 1e308 * 10.0hasil inf.

Catatan 2: karena kalkulasi apa pun dengan NaNpengembalian NaNdan perbandingan apa pun dengan NaN, termasuk NaNdirinya sendiri false, Anda harus menggunakan math.isnanfungsi ini untuk menentukan apakah suatu angka memang benar NaN.

Catatan 3: meskipun Python mendukung penulisan float('-NaN'), tanda diabaikan, karena tidak ada tanda pada NaNinternal. Jika Anda membagi -inf / +inf, hasilnya adalah NaNtidak -NaN(tidak ada hal seperti itu).

Catatan 4: berhati-hatilah untuk mengandalkan salah satu di atas, karena Python bergantung pada C atau Java library yang dikompilasi untuk dan tidak semua sistem yang mendasarinya menerapkan semua perilaku ini dengan benar. Jika Anda ingin memastikan, uji untuk tak terbatas sebelum melakukan perhitungan Anda.

¹) Baru-baru ini berarti sejak versi 3.2 .
²) Floating point mendukung nol positif dan negatif, jadi: x / float('inf')pertahankan tanda dan -1 / float('inf')hasil -0.0, 1 / float(-inf)hasil -0.0, 1 / float('inf')hasil 0.0dan -1/ float(-inf)hasil 0.0. Selain itu, 0.0 == -0.0adalahtrue , Anda harus memeriksa secara manual tanda jika Anda tidak ingin menjadi benar.

Abel
sumber
11
Nitpick kecil: tidak setiap perhitungan dengan infinity menghasilkan infinity:-1 * float('infinity') == -inf
Evan Krall
4
Itu sebabnya saya mengatakan itu adalah nitpick kecil . Anda membuat saya khawatir sebentar bahwa tanda itu akan benar-benar diabaikan ketika bekerja dengan tak terbatas, dan saya ingin mengklarifikasi untuk orang lain.
Evan Krall
12
Ya, hampir: 1 / float ('infinity') == 0.0
Phil
3
@ Phil: Walaupun saya cukup yakin Anda hanya berusaha menunjukkan bahwa tidak semua perhitungan dengan inf menghasilkan inf atau NaN, saya hanya ingin menjelaskan kepada orang lain yang mungkin membaca komentar, bahwa 1 / float ('infinity ') == 0,0 benar; karena, ketika Anda mendekati ketidakterbatasan, hasil dari divisi mendekati 0. Saya tahu itu hanya kalkulus dasar, tetapi saya ingin memastikan mereka yang membaca mengerti, atau setidaknya memiliki petunjuk mengapa, hasilnya adalah apa adanya.
Anthony Pace
1
Saya merasa bahwa jawaban ini jauh lebih baik daripada jawaban yang diterima.
Christian Herenz
3

Begitu juga C99 .

Representasi floating point IEEE 754 yang digunakan oleh semua prosesor modern memiliki beberapa pola bit khusus yang dicadangkan untuk infinity positif (tanda = 0, exp = ~ 0, frac = 0), infinity negatif (tanda = 1, exp = ~ 0, frac = 0 ), dan banyak NaN (Bukan Angka: exp = ~ 0, frac ≠ 0).

Yang perlu Anda khawatirkan: beberapa aritmatika dapat menyebabkan pengecualian / perangkap titik mengambang, tetapi itu tidak terbatas hanya pada konstanta "menarik" ini.

singkat
sumber
1
Jadi jika aritmatika saya terlalu besar, itu mungkin menjadi inf?
Casebash
@Casebash Tidak, itu akan menyebabkan OverflowError.
wizzwizz4
2

Saya menemukan peringatan yang sejauh ini tidak ada yang disebutkan. Saya tidak tahu apakah itu akan sering muncul dalam situasi praktis, tetapi ini demi kelengkapan.

Biasanya, menghitung angka tak terbatas modulo mengembalikan dirinya sebagai pelampung, tetapi sebagian kecil tak terbatas modulo kembali nan(bukan angka). Berikut ini sebuah contoh:

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

Saya mengajukan masalah pada pelacak bug Python. Itu dapat dilihat di https://bugs.python.org/issue32968 .

Pembaruan: ini akan diperbaiki dalam Python 3.8 .

Elias Zamaria
sumber
2

CAVEAT SANGAT BURUK: Divisi dengan Nol

dalam 1/xsepersekian, sampai saat x = 1e-323itu inftetapi ketika x = 1e-324atau sedikit itu melemparZeroDivisionError

>>> 1/1e-323
inf

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

jadi berhati-hatilah!

Seyfi
sumber