2010-01-24 15 views
5

Quindi, cPython (2.4) ha un comportamento interessante quando la lunghezza di qualcosa si avvicina a 1 < < 32 (la dimensione di un int).Python, len e dimensione degli interi

r = xrange(1<<30) 
assert len(r) == 1<<30 

va bene, ma:

r = xrange(1<<32) 
assert len(r) == 1<<32 
ValueError: xrange object size cannot be reported`__len__() should return 0 <= outcome 

Alex wowrange ha questo comportamento così. wowrange(1<<32).l va bene, ma len(wowrange(1<<32)) non funziona correttamente. Immagino che ci sia qualche azione in virgola mobile (che viene letta come negativa) in corso qui.

  1. Che cosa sta succedendo esattamente qui? (questo è abbastanza ben risolto di seguito!)
  2. Come posso aggirarlo? Longs?

(La mia domanda specifica è random.sample(xrange(1<<32),ABUNCH)) se la gente vuole affrontare direttamente a questa domanda!)

+0

@Gregg, abbastanza divertente ottengo OverflowError invece di ValueError (come fa l'A accettato a quella Q), ma, de minimis. Il problema è che, per la tua specifica applicazione, vuoi un 'random.sample' che non rientri nella memoria - ma ogni struttura Python ** deve ** adattarsi alla memoria. Se apri un'altra Q e specifichi i parametri in modo più dettagliato, forse è più pratico offrire assistenza per l'applicazione specifica ... –

+0

@Alex, in realtà, l'esempio non deve essere contenuto nella memoria, ma nella 2.4 (lo so, vecchie notizie!) modulo casuale, fa una chiamata len() che fallisce! xrange (1 << 32) di per sé va bene, ma la chiamata: n = len (popolazione) su 299 del modulo non lo è. –

+0

'random.sample' necessita' di chiamare len() 'anche in Python 2.5, 2.6, 3.0 e 3.1, e quella chiamata fallisce su' xrange (1 << 32) 'in ogni singola versione (poiché' len() 'si applica solo ai contenitori che" si adattano alla memoria "e che' xrange' concettualmente non lo fa). Quindi se specifichi meglio di cosa hai esattamente bisogno, esp. qual è il valore tipico di 'ABUNCH', possiamo suggerire come aggirare questa limitazione di' random.sample' (che si applica a tutte le versioni di Python!!). Meglio fare in un diverso Q, IMHO. –

risposta

11

cPython presuppone che gli elenchi siano in memoria. Questo si estende agli oggetti che si comportano come liste, come xrange. In sostanza, la funzione len prevede che il metodo __len__ restituisca qualcosa che è convertibile in size_t, che non si verificherà se il numero di elementi logici è troppo grande, anche se tali elementi non esistono effettivamente nella memoria.

+0

grazie per aver spiegato perché 'len' in particolare si comporta in questo modo. cPython len si aspetta 'size_t'. –

+0

Cavillo minore: solo perché una lunghezza è troppo grande per un 'size_t' non significa che l'oggetto non si adatti alla memoria. Ad esempio, ho una classe che rappresenta un campo di bit per cui '__len__' smette di funzionare per oggetti oltre 256 MB in Python a 32 bit. –

1

1<<32, quando trattata come un intero con segno, è negativo.

5

Troverete che

xrange(1 << 31 - 1) 

è l'ultima che si comporta come si desidera. Questo perché la massima firmato (32-bit) intero è 2^31 - 1.

1 << 32 non è un positivo segno a 32-bit integer (int tipo di dati di Python), quindi è per questo che stai ricevendo questo errore.

In Python 2.6, non riesco nemmeno a fare xrange(1 << 32) o xrange(1 << 31) senza ottenere un errore, molto meno len sul risultato.

Edit Se si vuole un po 'più in dettaglio ...

1 << 31 rappresenta il numero 0x80000000, che nella rappresentazione in complemento a 2 è il numero negativo rappresentabili più basso (-1 * 2^31) per un 32-bit int. Quindi sì, a causa della rappresentazione bit-a-bit dei numeri con cui stai lavorando, in realtà sta diventando negativo.

Per il numero di complemento a 32-bit 2, 0x7FFFFFFF è il numero intero rappresentabile più alto (2^31 - 1) prima di "overflow" in numeri negativi.

Further reading, se sei interessato.

Si noti che quando si visualizza qualcosa come 2147483648L nel prompt, la "L" alla fine significa che ora viene rappresentato come un "long integer" (64 bit, di solito, non posso fare promesse su come Python lo gestisce perché non ho letto su di esso).

+1

Prova 'hex (1 << 32)' e guarda cosa ottieni. Suggerimento: non è 0x80000000. –

+0

Typo, sorry, fixed. – Sapph

Problemi correlati