L'algoritmo di conversione da intero a stringa di Python utilizza un algoritmo semplicistico con un'esecuzione di O (n ** 2). Quando la lunghezza del numero raddoppia, il tempo di conversione quadruplica.
alcuni semplici test sul mio computer mostrano l'aumento del tempo di esecuzione:
$ time py35 -c "n=str(2**1000000)"
user 0m1.808s
$ time py35 -c "n=str(2**2000000)"
user 0m7.128s
$ time py35 -c "n=str(2**4000000)"
user 0m28.444s
$ time py35 -c "n=str(2**8000000)"
user 1m54.164s
Poiché l'esponente attuale è circa 10 volte più grande di mio ultimo valore di prova, si dovrebbe prendere circa 100 volte più a lungo. O poco più di 3 ore.
È possibile eseguire più rapidamente? Sì. Esistono diversi metodi più veloci.
Metodo 1
è più veloce per dividere il numero molto elevato da un numero approssimativamente uguale grandezza ma piccole potenze di 10 in due. Il processo viene ripetuto fino a quando i numeri sono relativamente piccoli. Quindi su ogni numero viene utilizzato str()
e gli zeri iniziali vengono utilizzati per applicare il risultato alla stessa lunghezza dell'ultima potenza di 10. Quindi le corde vengono unite per formare il risultato finale. Questo metodo è utilizzato dalla libreria mpmath
e la documentazione implica che dovrebbe essere circa 3 volte più veloce.
Metodo 2
interi di Python sono memorizzati in formato binario. Il binario è ottimo per i calcoli ma la conversione da binaria a decimale è il collo di bottiglia. È possibile definire il proprio tipo intero che memorizza il valore in blocchi di 100 cifre decimali (o un valore simile). Le operazioni (esponenziazione, moltiplicazione, divisione) saranno più lente ma la conversione in una stringa sarà molto veloce.
Molti anni fa, ho implementato tale classe e utilizzato algoritmi efficienti per la moltiplicazione e la divisione. Il codice non è più disponibile su Internet ma ho trovato una copia di backup che ho testato. Il tempo di esecuzione è stato ridotto a ~ 14 secondi.
Aggiornamento
Ho aggiornato il codice di riferimento DecInt sopra ed è ora disponibile a https://github.com/casevh/DecInt.
Se viene utilizzato il tipo intero nativo di Python, il tempo di esecuzione totale è inferiore a 14 secondi sul computer. Se invece viene usato il tipo intero gmpy2
, il tempo di esecuzione è di ~ 3,5 secondi.
$ py35 DecInt.py
Calculating 2^74207281
Exponentiation time: 3.236
Conversion to decimal format: 0.304
Total elapsed time: 3.540
Length of result: 22338618 digits
Metodo 3
mantengo la biblioteca gmpy2 che forniscono un facile accesso alla biblioteca GMP per l'aritmetica intero veloce. GMP implementa il Metodo 1 nel codice C e assembly altamente ottimizzato e calcola il numero primo e la rappresentazione della stringa in ~ 5 secondi.
Metodo 4
Il modulo decimal
in Python memorizza valori come cifre decimali. Le versioni recenti di Python 3 includono un'implementazione C della libreria decimale che è molto più veloce che l'implementazione di pure-Python include con Python 2. L'implementazione C viene eseguita in poco più di 3 secondi sul mio computer.
from decimal import *
getcontext().prec = 23000000
getcontext().Emin = -999999999
getcontext().Emax = 999999999
x=Decimal(2)**74207281 - 1
s=str(x)
Bene, a 100 cifre al secondo si dovrebbe finire in circa 6 ore, quindi questa soluzione sembra fattibile. Forse dividi per 1000000 alla volta e ottieni 6 cifre contemporaneamente? – HugoRune
Questa soluzione ti darà le cifre in ordine inverso. –
@FrerichRaabe Grazie per avermi fatto sapere, anche se penso che sarebbe abbastanza banale invertirlo di nuovo. – Daffy