Menangani angka yang sangat besar dengan Python

143

Saya telah mempertimbangkan evaluasi tangan poker cepat dengan Python. Terpikir oleh saya bahwa salah satu cara untuk mempercepat prosesnya adalah dengan merepresentasikan semua wajah dan corak kartu sebagai bilangan prima dan mengalikannya untuk merepresentasikan tangan. Sedikit pun:

class PokerCard:
    faces = '23456789TJQKA'
    suits = 'cdhs'
    facePrimes = [11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 53, 59, 61]
    suitPrimes = [2, 3, 5, 7]

DAN

    def HashVal(self):
      return PokerCard.facePrimes[self.cardFace] * PokerCard.suitPrimes[self.cardSuit]

Ini akan memberi setiap tangan nilai numerik yang, melalui modulo bisa memberi tahu saya berapa banyak raja di tangan atau berapa banyak hati. Misalnya, setiap tangan dengan lima atau lebih klub di dalamnya akan dibagi rata dengan 2 ^ 5; tangan mana pun dengan empat raja akan membagi rata dengan 59 ^ 4, dll.

Masalahnya adalah bahwa tujuh kartu seperti AcAdAhAsKdKhKs memiliki nilai hash sekitar 62,7 kuadriliun, yang akan membutuhkan lebih dari 32 bit untuk diwakili secara internal. Apakah ada cara untuk menyimpan bilangan besar dengan Python yang memungkinkan saya melakukan operasi aritmatika?

Ya - Jake itu.
sumber
14
Apakah Anda yakin bahwa, setelah Anda mulai menampilkan data dengan cara ini, Anda masih akan melihat peningkatan kecepatan yang signifikan? Saya menyadari ini tidak menjawab pertanyaan Anda, tapi tetap ..
Thomi
3
Saya punya saran: daripada menggunakan variabel terpisah untuk nilai kartu dan representasi, saya menyarankan menggunakan kamus. (Jadi wajah = {'2': 11, '3': 13, '4': 17, '5': 19, '6': 23, '7': 29, '8': 31, '9' : 37, 'T': 41, 'J': 43, 'Q': 53, 'K': 59, 'A': 61} dan suit = {'c': 2, 'd': 3, ' h ': 5,' s ': 7}.)
JAB

Jawaban:

183

Python mendukung tipe integer "bignum" yang dapat bekerja dengan bilangan besar secara sembarangan. Dalam Python 2.5+, tipe ini dipanggil longdan terpisah dari inttipenya, tetapi interpreter akan secara otomatis menggunakan mana yang lebih sesuai. Di Python 3.0+, intjenisnya telah dihapus sepenuhnya.

Itu hanya detail implementasi, meskipun - selama Anda memiliki versi 2.5 atau lebih baik, cukup lakukan operasi matematika standar dan angka apa pun yang melebihi batas matematika 32-bit akan secara otomatis (dan transparan) diubah menjadi bignum.

Anda dapat menemukan semua detail berdarah di PEP 0237 .

Ben Blank
sumber
2
Pertanyaannya adalah, apakah kinerja yang dicapai dari penggunaan bignum alih-alih bilangan bulat 32 bit melebihi manfaat kinerja dari metode pintar evaluasi tangan yang dia gunakan.
Chris Upchurch
3
Sebenarnya, pembatas antara int dan long telah ditembus di 2.5. 3.0 menghapus int sama sekali, membuat panjang satu-satunya tipe integer.
Ignacio Vazquez-Abrams
1
Seberapa besar angka besar? Bisakah PHI ^ 4000000?
Mike Caron
9
@ Mike Caron - Jika struct yang tercantum dalam PEP 0237 akurat, longpanjang s (dalam digit) disimpan sebagai bilangan bulat 32-bit unsigned, hingga 4.294.967.295 digit, yang berarti dapat dengan mudah menampung φ ** (4 * 10 ** 6 ), yang "hanya" 832.951 digit. Namun, φ bukanlah bilangan bulat, jadi Anda perlu menggunakan Desimal (bignum floating-point Python) untuk menghitung angka tersebut. Anda dapat menyimpan hasilnya longnanti.
Ben Blank
17
@ IgnacioVazquez-Abrams Hanya satu poin klarifikasi, longadalah satu-satunya tipe bilangan bulat di 3.0, tetapi dinamai int. (Dan yang lama inthilang.)
Michael Mior
77

python mendukung sewenang-wenang besar bilangan bulat secara alami:

contoh:

>>> 10**1000
10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

Anda bahkan bisa mendapatkan, misalnya nilai integer yang sangat besar, fib (4000000).

Tapi tetap saja tidak (untuk saat ini) mendukung float besar yang sewenang-wenang !!

Jika Anda membutuhkan satu besar, besar, pelampung kemudian periksa Modul desimal. Ada contoh penggunaan pada forun ini: OverflowError: (34, 'Result too large')

Referensi lain: http://docs.python.org/2/library/decimal.html

Anda bahkan dapat menggunakan modul gmpy jika Anda membutuhkan percepatan (yang mungkin menarik bagi Anda): Menangani angka besar dalam kode

Referensi lain: https://code.google.com/p/gmpy/

Nuno Aniceto
sumber
35

Anda bisa melakukan ini untuk kesenangan, tapi selain itu itu bukan ide yang bagus. Itu tidak akan mempercepat apapun yang dapat saya pikirkan.

  • Mendapatkan kartu di tangan akan menjadi operasi pemfaktoran bilangan bulat yang jauh lebih mahal daripada hanya mengakses array.

  • Menambahkan kartu akan menjadi perkalian, dan menghapus pembagian kartu, keduanya dari bilangan multi-kata besar, yang merupakan operasi yang lebih mahal daripada menambah atau menghapus elemen dari daftar.

  • Nilai numerik sebenarnya dari sebuah tangan tidak akan memberi tahu Anda apa pun. Anda perlu memfaktorkan bilangan prima dan mengikuti aturan Poker untuk membandingkan dua tangan. h1 <h2 untuk tangan seperti itu tidak ada artinya.


sumber
27

python mendukung bilangan bulat besar secara alami:

In [1]: 59**3*61**4*2*3*5*7*3*5*7
Out[1]: 62702371781194950
In [2]: _ % 61**4
Out[2]: 0
Autoplektik
sumber
4

Penerjemah python akan menanganinya untuk Anda, Anda hanya perlu melakukan operasi Anda (+, -, *, /), dan itu akan berfungsi seperti biasa.

The intnilai tidak terbatas.

Hati-hati saat melakukan pembagian, secara default hasil bagi berubah menjadi float, tetapi floattidak mendukung angka yang begitu besar. Jika Anda mendapatkan pesan kesalahan yang mengatakan floattidak mendukung angka yang begitu besar, maka itu berarti hasil bagi terlalu besar untuk disimpan di floatAnda harus menggunakan pembagian lantai ( //).

Ini mengabaikan desimal apa pun yang muncul setelah koma desimal, dengan cara ini, hasilnya adalah int, sehingga Anda bisa mendapatkan hasil angka yang besar.

>>>10//3
3

>>>10//4
2
Hedy
sumber
1
Bagaimana jawaban Anda mengatasi masalah nomor besar dalam pertanyaan?
StupidWolf
Ini berarti Anda bisa melakukan operasi normal dengan jumlah besar tetapi hati-hati dengan pembagian
Hedy