Gestire numeri molto grandi in Python


140

Ho preso in considerazione una rapida valutazione della mano di poker in Python. Mi è venuto in mente che un modo per accelerare il processo sarebbe quello di rappresentare tutte le facce e semi delle carte come numeri primi e moltiplicarli insieme per rappresentare le mani. Per Pentecoste:

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]

E

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

Ciò darebbe ad ogni mano un valore numerico che, attraverso il modulo, potrebbe dirmi quanti re ci sono nella mano o quanti cuori. Ad esempio, ogni mano con cinque o più fiori dentro si dividerebbe uniformemente per 2 ^ 5; qualsiasi mano con quattro re si dividerebbe uniformemente per 59 ^ 4, ecc.

Il problema è che una mano di sette carte come AcAdAhAsKdKhKs ha un valore di hash di circa 62,7 quadrilioni, che richiederebbe considerevolmente più di 32 bit per rappresentare internamente. C'è un modo per memorizzare numeri così grandi in Python che mi permetterà di eseguire operazioni aritmetiche su di esso?


13
Sei sicuro che, una volta che inizi a rappresentare i tuoi dati in questo modo, vedrai comunque un significativo miglioramento della velocità? Mi rendo conto che questo non risponde alle tue domande, ma comunque ...
Thomi,

3
Ho un suggerimento: invece di usare variabili separate per i valori delle carte e le rappresentazioni, suggerisco di usare dizionari. (So ​​faces = {'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} e semi = {'c': 2, 'd': 3, ' h ': 5,' s ': 7}.)
JAB il

Risposte:


177

Python supporta un tipo intero "bignum" che può funzionare con numeri arbitrariamente grandi. In Python 2.5+, questo tipo viene chiamato longed è separato dal inttipo, ma l'interprete utilizzerà automaticamente quello che è più appropriato. In Python 3.0+, il inttipo è stato eliminato completamente.

Questo è solo un dettaglio dell'implementazione, tuttavia, finché hai la versione 2.5 o superiore, esegui solo operazioni matematiche standard e qualsiasi numero che superi i limiti della matematica a 32 bit verrà automaticamente (e trasparente) convertito in un bignum.

Puoi trovare tutti i dettagli cruenti in PEP 0237 .


2
La domanda è: il colpo di prestazione derivante dall'uso di bignum invece di numeri interi a 32 bit supera il vantaggio prestazionale derivante dal metodo intelligente di valutazione manuale che sta usando.
Chris Upchurch,

3
In realtà, la barriera tra int e long è stata rotta in 2.5. 3.0 rimuove del tutto int, rendendo a lungo l'unico tipo intero.
Ignacio Vazquez-Abrams,

1
Quanto è grande un grande num? Può essere PHI ^ 4000000?
Mike Caron,

9
@Mike Caron - Se la struttura elencata in PEP 0237 è accurata, longle lunghezze di s (in cifre) sono memorizzate come numeri interi a 32 bit senza segno, fino a 4.294.967.295 cifre, il che significa che possono contenere facilmente φ ** (4 * 10 ** 6 ), che è "solo" 832.951 cifre. Tuttavia, φ non è un numero intero, quindi dovrai usare un decimale (bignum in virgola mobile di Python) per calcolare il numero. longTuttavia, è possibile memorizzare il risultato in un secondo momento.
Ben Blank,

17
@ IgnacioVazquez-Abrams Solo un punto di chiarimento, longè l'unico tipo intero in 3.0, ma è chiamato int. (E il vecchio non intc'è più.)
Michael Mior il

70

python supporta naturalmente numeri interi arbitrariamente grandi :

esempio:

>>>10 ** 1000 100000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

Potresti persino ottenere, ad esempio, un enorme valore intero, fib (4000000).

Ma ancora lo fa , non (per ora) supporta un numero arbitrariamente grande galleggiante !!

Se hai bisogno di un float grande, grande, controlla il modulo decimale. Ci sono esempi d'uso su questi foruns: OverflowError: (34, 'Result too large')

Un altro riferimento: http://docs.python.org/2/library/decimal.html

Puoi anche usare il modulo gmpy se hai bisogno di una accelerazione (che probabilmente sarà di tuo interesse): Gestire grandi numeri nel codice

Un altro riferimento: https://code.google.com/p/gmpy/


33

Potresti farlo per divertirti, ma a parte questo non è una buona idea. Non accelererebbe nulla a cui riesco a pensare.

  • Ottenere le carte in una mano sarà un'operazione di factoring intero che è molto più costosa del semplice accesso ad un array.

  • L'aggiunta di carte sarebbe una moltiplicazione e la rimozione della divisione delle carte, entrambi con grandi numeri di più parole, che sono operazioni più costose rispetto all'aggiunta o alla rimozione di elementi dagli elenchi.

  • Il valore numerico effettivo di una mano non ti dirà nulla. Dovrai fattorizzare i numeri primi e seguire le regole del poker per confrontare due mani. h1 <h2 per tali mani non significa nulla.


25

python supporta naturalmente numeri interi arbitrariamente grandi:

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

3

L'interprete Python lo gestirà per te, devi solo fare le tue operazioni (+, -, *, /) e funzionerà normalmente.

Il intvalore è illimitato

Attento quando si esegue la divisione, per impostazione predefinita il quoziente viene trasformato in float, ma floatnon supporta numeri così grandi. Se ricevi un messaggio di errore che dice floatche non supporta numeri così grandi, significa che il quoziente è troppo grande per essere archiviato, floatdovrai usare la divisione floor ( //).

Ignora qualsiasi decimale che segue il punto decimale, in questo modo il risultato sarà int, in modo da poter ottenere un numero elevato.

10//3 Uscite 3

10//4 uscite 2


1
In che modo la tua risposta risolve il problema dei numeri grandi nella domanda?
Stupid Wolf,

Significa che puoi semplicemente fare le normali operazioni con grandi numeri, ma fai attenzione con la divisione
Hedy,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.