2009-12-02 4 views
4

J'ai besoin d'un algorithme plus rapide que la multiplication longue normale de Python.Python longue multiplication

J'ai essayé de trouver une implémentation décente de Karatsuba, mais je ne peux pas.

def main(): 
    a=long(raw_input()) 
    if(a<0): 
     a=a*-1 
     a=((a*(a+1)/2)-1) 
     print(-a) 
    else: 
     a=(a*(a+1))/2 
     print(a) 
main() 

Comme vous le voyez, ce n'est rien de compliqué, juste quelques multiplications. Mais il doit gérer des nombres allant jusqu'à 100 000 chiffres en moins de 2,5 secondes. Je voudrais un extrait d'une fonction ou juste un lien vers une implémentation d'une fonction de multiplication plus rapide, ou tout ce qui aide.

+0

Je pense que Python utilise déjà karatsuba sous le capot (lorsqu'il est déclenché par beaucoup de chiffres) ... – ChristopheD

+0

Python utilise déjà karatsuba pour une longue multiplication. L'impression prendra beaucoup plus de temps que la multiplication. –

+0

Est-ce correct d'imprimer (hex (a)) '? Ce sera beaucoup plus rapide que 'print (a)' –

Répondre

2

Vous pouvez jeter un oeil à la mise en œuvre de la DecInt module (version pure Python est disponible (Toom-Cook), mais le plus rapide, il sera probablement en utilisant gmpy).

+0

Thans, j'ai copié toute la librairie dans mon code, l'ai un peu ajusté pour réduire la taille donc ça tient dans 64 Ko et alto ça marche: D – Nedim

+0

Si ces algorithmes sont plus rapides, pourquoi ne sont-ils pas implémentés en python? –

+1

@Nedim: "copié toute la bibliothèque dans mon code"? "réduire la taille de sorte que [quoi?] correspond à 64 Ko"? "alto"?Vous êtes en effet sui generis :-) –

3

Je suggère que vous obteniez le Sage math tool, qui a à peu près tous les outils de mathématiques Python jamais faits en un seul paquet. Voyez s'il existe dans Sage un bon outil mathématique de précision rapide et arbitraire qui répond à vos besoins.

+0

Merci pour la réponse, mais le problème est que j'ai besoin d'une implémentation directe, pas de bibliothèques - ce qui signifie que j'ai besoin de la fonction être capable de prendre 2 longs et retourner un troisième à temps. J'ai jeté un coup d'oeil à l'algorithme de multiplication de Toom-Cook, mais je ne peux pas trouver une implémentation adéquate. – Nedim

+0

@Nedim: Ummm pas de bibliothèques, donc si vous trouvez une implémentation "adéquate" d'un algorithme différent, vous allez pirater votre version de Python ?? Combien de temps pensez-vous qu'un appel à une routine de bibliothèque prendrait? –

+0

En fait, je ne sais pas, je veux juste quelque chose comme une fonction dans mon script/programme principal. Je ne code pas souvent en Python, j'ai fait jusqu'à présent 10 à 20 programmes et surtout des plus courts pour calculer des trucs, je code principalement en C/C++ donc je ne sais pas vraiment à quoi m'attendre de Python. J'ai utilisé python en raison de la commodité des bigints. – Nedim

9

15,9 ms sur mon ordinateur portable lent. C'est l'impression qui vous ralentit. La conversion en nombre binaire en décimal est assez lente, ce qui est une étape nécessaire pour l'imprimer. Si vous avez besoin de sortir le numéro, vous devriez déjà essayer DecInt ChristopheD.

DecInt sera plus lent à faire la multiplication, mais rendre l'impression beaucoup plus rapide

In [34]: a=2**333000 

In [35]: len(str(a)) 
Out[35]: 100243 

In [36]: b=2**333001 

In [37]: len(str(b)) 
Out[37]: 100244 

In [38]: timeit c=a*b 
10 loops, best of 3: 15.9 ms per loop 

Voici un exemple avec une version légèrement modifiée de votre code. Notez que la conversion d'une chaîne de chiffres 100000 à une longue prend déjà ~ 1sec sur cet ordinateur

In [1]: def f(a): 
    ...:  if(a<0): 
    ...:   a=a*-1 
    ...:   a=((a*(a+1)/2)-1) 
    ...:  else: 
    ...:   a=(a*(a+1))/2 
    ...:  return a 
    ...: 

In [2]: a=3**200000 

In [3]: len(str(a)) 
Out[3]: 95425 

In [4]: timeit f(a) 
10 loops, best of 3: 417 ms per loop 
+0

Savez-vous un moyen plus rapide d'imprimer les résultats à la console? – Nedim

+3

+1: pour mesurer réellement les performances * avant * d'essayer d'optimiser – jfs

+0

@Nedim: les ordinateurs parlent binaire. vous pouvez convertir binaire et hexadécimal très simplement et rapidement (4 bits à la fois). Il n'y a pas de raccourci comme ça pour convertir en décimal, donc c'est beaucoup plus lent. Si vous pouvez vous en tirer en utilisant hexadécimal pour l'entrée et la sortie, vous n'avez pas besoin de ces conversions décimales lentes –

24

Je suis l'auteur de la bibliothèque DecInt (entier décimal) donc je vais faire quelques commentaires.

La bibliothèque DecInt a été spécialement conçue pour fonctionner avec de très grands entiers devant être convertis au format décimal. Le problème avec la conversion au format décimal est que la plupart des bibliothèques de précision arbitraire stockent des valeurs en binaire. C'est le plus rapide et le plus efficace pour utiliser la mémoire, mais la conversion de binaire en décimal est généralement lente. La conversion binaire en décimal de Python utilise un algorithme O (n^2) et ralentit très rapidement.

DecInt utilise une grande base décimale (généralement 10^250) et stocke le très grand nombre dans des blocs de 250 chiffres. La conversion d'un très grand nombre au format décimal est maintenant exécutée dans O (n). Naïf, ou école primaire, la multiplication a un temps d'exécution de O (n^2). Python utilise la multiplication de Karatsuba qui a le temps d'exécution de O (n^1.585). DecInt utilise une combinaison de convolutions de Karatsuba, de Toom-Cook et de Nussbaumer pour obtenir un temps de fonctionnement de O (n * ln (n)).

Même si DecInt a un surdébit beaucoup plus élevé, la combinaison de la multiplication O (n * ln (n)) et de la conversion O (n) sera plus rapide que la multiplication O (n^1.585) et O (n^2)) conversion.

Comme la plupart des calculs ne nécessitent pas l'affichage de tous les résultats au format décimal, presque toutes les bibliothèques de précision arbitraire utilisent des binaires car cela facilite les calculs. DecInt vise un très petit créneau. Pour des nombres assez grands, DecInt sera plus rapide pour la multiplication et la division que Python natif. Mais si vous recherchez une performance pure, une librairie comme GMPY sera la plus rapide.

Je suis content que vous ayez trouvé DecInt utile.