2012-01-23 8 views
5

Sto facendo un enigma in cui devo occuparmi dei numeri dell'ordine 10^18. Tuttavia, trovo Python non è in grado di gestire numeri molto grandi in tutte le aree.Perché python non gestisce numeri molto grandi in tutte le aree?

Per essere precisi, se assegniamo a = 1000000000000000000 (10^18) e facciamo i calcoli aritmetici di base (+, -, /, *), la sua risposta. Tuttavia, la sua mostrando OverflowError quando lo uso nella gamma()

>>> a = 1000000000000000000 
>>> a/2 
500000000000000000L 
>>> a*2 
2000000000000000000L 
>>> a+a 
2000000000000000000L 
>>> a*a 
1000000000000000000000000000000000000L 
>>> range(a) 

Traceback (most recent call last): 
    File "<pyshell#5>", line 1, in <module> 
    range(a) 
OverflowError: range() result has too many items 
>>> xrange(a) 

Traceback (most recent call last): 
    File "<pyshell#6>", line 1, in <module> 
    xrange(a) 
OverflowError: Python int too large to convert to C long 

ho usato Python 2.7.

  1. Come posso gestire tali casi ?, Qual è il modo migliore per gestire i puzzle che contengono tali numeri. (Un riferimento tutorial/libro sarebbe apprezzato)
  2. Perché Python non è in grado di gestire la cosa in range()/xrange()

mi piacerebbe farlo in python 2.7 utilizzando le funzioni inbuild. Non è possibile?

+2

Possibile duplicato http://stackoverflow.com/questions/1482480/xrange2100-overflowerror-long-int-too-large-to-vert-to-int –

+2

Dubito che stai andando a risolvere il tuo puzzle nel modo giusto . Il conteggio fino a 10^18 con python su un computer di oggi richiederebbe un ordine nell'ordine di 10000 anni. –

+0

itertools.count() sembra essere un'opzione, ma il conteggio richiede molto tempo. C'è qualche altra opzione efficiente (considerando le situazioni in cui dobbiamo contare grandi valori, risolvendo enigmi) – Surya

risposta

10

In Python 2.x, range e xrange sono limitati a lavorare con C long e le tue grandi numeri interi sono semplicemente troppo grande per questo. Questa limitazione è semplicemente dovuta alle scelte di implementazione effettuate per range e xrange.

In Python 3.x la limitazione è stata rimossa ed è possibile eseguire range() con numeri interi molto grandi.

>>> range(2**128) 
range(0, 340282366920938463463374607431768211456) 

Il official list of changes for Python 3 ha questo da dire:

range() ora si comporta come xrange() utilizzato a comportarsi, se non funziona con valori di dimensione arbitraria. Quest'ultimo non esiste più.


In Python 2.x la funzione range() restituito un elenco. Chiaramente non c'è speranza di allocare memoria per tutti gli elementi per gamme molto grandi. La funzione xrange() restituisce un oggetto xrange. Lo documentation lo descrive come "un tipo di sequenza opaca che restituisce gli stessi valori dell'elenco corrispondente, senza memorizzarli tutti contemporaneamente". La documentazione continua a dire questo:

xrange() è progettato per essere semplice e veloce. Le implementazioni possono imporre restrizioni per raggiungere questo obiettivo. L'implementazione C di Python limita tutti gli argomenti agli interi C nativi ("brevi" interi Python) e richiede anche che il numero di elementi si adatti a un C nativo.

Questo spiega le limitazioni in Python 2.x.


io non sono abbastanza sicuro che cosa si può utilmente fare con il nuovo Python 3 il supporto per grandi intervalli. Ad esempio, non ti consiglio di provare questo:

2**128 in range(2**128) 

Che funzionerà a lungo.


Nei commenti si indica che si sta scrivendo il codice per contare fino a un numero elevato. È possibile farlo banalmente in Python con codice come questo:

i = 0 
while i<N: 
    doSomething(i) 
    i += 1 

Ma si scopre che, se N è un gran numero allora questo ci vorrà un tempo molto lungo. Non c'è nulla di scontato per i valori di N dell'ordine 2 come da domanda.

+0

Penso che dovrei trovare un altro modo per la soluzione poiché raggiungere N è in genere impossibile. – Surya

+0

Esatto. Non puoi aspettarti di contare fino a 2^18. –

+2

Minore: nel moderno Python 3, '2 ** 128 in range (2 ** 128)' verrà eseguito istantaneamente perché '__contains__' è stato creato in modo speciale. – DSM

1

Il tuo problema è che range() in Python 2.7 costruisce un elenco esplicito di ogni valore nell'intervallo - semplicemente non hai abbastanza risorse per costruire un tale elenco.

Python 3 corregge questo comportamento e calcola solo i valori su richiesta ... come se fossero un'espressione di generatore.

La funzione Python 2 xrange() non ti aiuterà in quanto è vincolata alla registrazione dei valori ... che era un compromesso per Python 2 per evitare l'enorme overhead di range() per tutti i numeri che non sono banalmente piccolo

Un approccio potrebbe essere quello di definire il proprio generatore che itera su interi arbitrari - qualcosa come:

def genrange(min,max,stride=1): 
    val=min 
    while val<max: 
     yield val 
     val+=stride 

Il mio sospetto, tuttavia, è che questo è probabilmente un errore nel grande schema delle cose - come si È improbabile che dispongano di risorse di elaborazione sufficienti per scorrere ogni valore di un intero a 32 bit, per non parlare di un intervallo intero più grande di quello di un registro (a 32 bit). Sospetto che ci sia un modo migliore per affrontare il tuo problema che non dipende da un intervallo in primo luogo.

+0

Potrebbe essere un modo (potrebbe non essere efficiente) per avere una funzione come range(). Tuttavia, avrei potuto usare immediatamente while() piuttosto che metterlo in una funzione. Penso che ridurrebbe anche la complessità del tempo. (Non sono sicuro) – Surya

Problemi correlati