Avec le récent dénigrement de Python , voici une tentative pour montrer les points forts de Python. Votre défi est d'écrire un programme qui calcule la factorielle d'un nombre aussi élevé que possible en 10 secondes.n
Votre score sera (highest n for your program on your machine)/(highest n for my program on your machine)
Règles
- Vous devez calculer une solution entière exacte. Étant donné que la factorielle serait beaucoup plus élevée que ce qui peut tenir dans un entier non signé 64 bits, vous pouvez utiliser des chaînes si votre langue ne prend pas en charge les grands entiers
- Les failles standard sont interdites. En particulier, vous ne pouvez utiliser aucune ressource externe.
- Seule la partie calcul (qui inclut le temps pour toutes les solutions de contournement utilisant des chaînes) s'ajoute au temps total qui doit être inférieur à 10 secondes en moyenne.
- Programmes à thread unique uniquement.
- Vous devez stocker la sortie sous une forme facilement imprimable (car l'impression prend du temps) (voir mon programme ci-dessous), chaîne, variable, tableau de caractères, etc.
ÉDITER:
- Votre programme doit donner la sortie correcte pour tous
n
:1 <= n <= (your highest n)
EDIT2:
- Je déteste le dire explicitement, mais l'utilisation des fonctions factorielles intégrées de votre langage relève des lacunes standard http://meta.codegolf.stackexchange.com/a/1078/8766 Désolé Mathematica et Sage
Mon programme
from __future__ import print_function
import time
def factorial( n ):
return reduce( ( lambda x , y : x * y ) , xrange( 1 , n + 1 ) , 1 )
start = time.clock()
answer = factorial( 90000 )
end = time.clock()
print ( answer )
print ( "Time:" , end - start , "sec" )
Le score le plus élevé l'emporte. Pour mémoire, mon code peut se gérer n = 90000
en 9.89
quelques secondes sur un Pentium 4 3.0 GHz
EDIT: Tout le monde peut-il s'il vous plaît ajouter le score plutôt que le n le plus élevé . Le plus haut n
n'a aucune signification en soi car il dépend de votre matériel. Sinon, il est impossible d'avoir un critère de gain objectif. La réponse de ali0sha le fait correctement.
Nous avons un gagnant. Je n'ai pas accepté la réponse java /codegolf//a/26974/8766 car il s'agit de jupes proches de http://meta.codegolf.stackexchange.com/a/1080/8766
la source
operator.mul
place de la fonction lambdafactorial(Inf)
retourneInf
en une fraction de seconde.Réponses:
C ++ avec GMP, score = 55,55 (10 000 000/180 000)
la source
Python 2.7
42.575 = (6.812.000 / 160.000) environ
Code:
Tester:
Production:
Comment ça fonctionne:
De plus grandes multiplications prennent plus de temps, nous voulons donc faire autant de petites multiplications que possible. Cela est particulièrement vrai en Python où pour des nombres inférieurs,
2^64
nous utilisons l'arithmétique matérielle, et surtout que nous utilisons des logiciels. Donc, dansm(L)
, nous commençons par une listeL
; si c'est une longueur impaire, nous supprimons un nombre de considération pour le rendre encore une fois. Ensuite, nous multiplions élément1
par élément-2
, élément3
avec-4
, etc., de sorte queCette approche garantit que nous utilisons l'arithmétique matérielle aussi longtemps que possible, après quoi nous basculons sur la bibliothèque arithmétique gmc efficace.
Dans
fac2
, nous adoptons également une approche de division et de conquête plus classique, où nous séparons chaque multiple de 2 et les décalons à la fin pour une amélioration des performances triviale. Je l'ai inclus ici car il est généralement environ 0,5% plus rapide quefac1
.Version golfée de
fac1
(parce que je peux), 220Bla source
gmpy2
? $ python Python 2.7.3 (par défaut, 27 février 2014, 19:58:35) [GCC 4.6.3] sur linux2 Tapez "help", "copyright", "credits" ou "license" pour plus d'informations. >>> depuis gmpy2 import mpz Traceback (dernier appel le plus récent): Fichier "<stdin>", ligne 1, dans <module> ImportError: Aucun module nommé gmpy2 >>>while len(L): ...
place dewhile len(L)>1: ...
?Java - 125,15 (21 400 000/ 171 000)
Également copié sans vergogne à partir du référentiel Github de Peter Luschny (merci @ semi-extrinsèque) et autorisé sous la licence MIT, il utilise l'algorithme de "quadrillage imbriqué à factorisation principale" tel que proposé par Albert Schönhage et al. (selon la page de description des algorithmes factoriels de Luschny ).
J'ai légèrement adapté l'algorithme pour utiliser BigInteger de Java et pour ne pas utiliser de table de recherche pour n <20.
Compilé avec gcj, qui utilise GMP pour son implémentation BigInteger, et exécuté sur Linux 3.12.4 (Gentoo), sur un Core i7 4700MQ à 2,40 GHz
la source
gcj -O3 --main=PrimeSieveFactorialSchoenhage PrimeSieveFactorialSchoenhage.java -o pf_nest_square_fact
Python 3, n = 100000
Un simple changement d'algorithme était tout ce qui était nécessaire pour augmenter l'exemple de code de 10000.
Évidemment, ce n'est pas la réponse la plus créative, mais il n'y a vraiment qu'une seule façon de faire une factorielle ...
la source
Perl + C, n = environ 3 millions
Ici, j'utilise la bibliothèque Math :: BigInt :: GMP disponible sur CPAN, qui fournit une augmentation de vitesse massive pour les principaux objets Math :: BigInt de Perl.
Gardez à l'esprit que mon ordinateur est probablement un peu plus lent que le vôtre. En utilisant votre script Python d'origine, je ne peux calculer
factorial(40000)
qu'en 10 secondes;factorial(90000)
prend beaucoup plus de temps. (J'appuie sur Ctrl + C après une minute.) Sur votre matériel, en utilisant Math :: BigInt :: GMP, vous pouvez très bien calculer la factorielle de 5 millions ou plus en moins de 10 secondes.Une chose que vous remarquerez peut-être, c'est que même si la factorielle est calculée incroyablement rapidement, l'impression du résultat est très lente, prenant environ trois fois plus longtemps que le calcul d'origine. En effet, GMP utilise en interne une représentation binaire plutôt que décimale et son impression nécessite une conversion binaire en décimale.
la source
Math::BigInt
Python 2,7
5,94 = 1'200'000 / 202'000
Utilise la facilité relative de multiplication de nombreux groupes de petits nombres, puis les multiplie par rapport à un grand nombre de multiplications impliquant un nombre énorme.
la source
C #: 0,48 (77 000/160 000)
Je ne suis pas content de ça.
C # est-il si lent?
Mais voici quand même mon entrée.
Lorsque n = 77000, il faut
00:00:09:8708952
calculer.J'exécute en mode Release, en dehors de Visual Studio, en utilisant un Core i3-2330M @ 2,2 GHz.
Edit: Puisque je ne fais rien d'intelligent, j'accepte ce résultat. Peut-être que le .NET Framework 4.5 ajoute des frais généraux (ou BigInteger n'est pas si rapide).
la source
n
zero approached by
opérateur pour le rendre plus joli (comme commencer parn = ... + 1
puis fairewhile (0 <-- n) result *= n;
)bc, score = 0,19
Que diable, voici mon candidat pour "Combien pouvez-vous multiplier lentement?"
bc est "un langage de calculatrice à précision arbitraire", mais malheureusement assez lent:
En environ 10 secondes sur mon MacBook Pro mi-2012 (Intel Core i7 à 2,3 GHz), la réponse de référence en python peut calculer 122000 !, mais ce script bc ne peut calculer que 23600 !.
Inversement 10000! prend 1,5s avec le script de référence python, mais le script bc prend 50s.
Oh cher.
la source
read()
, alors j'ai courutime sed 's/read()/28000/' factorial.bc | bc
.Bash: score = 0,001206 (181/150000)
J'ai volé les fonctions mathématiques de Rosettacode - Longue multiplication que je n'ai pas analysé ni essayé d'optimiser.
Vous êtes libre de modifier l'algorithme ou d'essayer une méthode de fractionnement de chaînes différente.
la source
Python 3, algo avancé de Peter Luschny: 8,25x (1 280 000/155 000)
Copie sans vergogne de Peter Luschny,
http://www.luschny.de/math/factorial/FastFactorialFunctions.htm ,
qui fournit ce code sous la licence "Creative Commons Attribution-ShareAlike 3.0".
Il s'agit en fait d'un algorithme assez avancé, utilisant quelque chose appelé "factoriel oscillant" et une liste de nombres premiers. Je soupçonne que cela pourrait être encore plus rapide s'il aimait la plupart des autres réponses et effectuait la plupart des multiplications avec des entiers 32 bits.
la source
Java - 10,9
n = 885000
Mergesort-y.
BigInteger
s sont lents.Recommandations pour les bibliothèques d'entiers Java à haute vitesse de précision arbitraire? : P
la source
C ++ (spécifique à x86_64) - 3.0 (390000/130000)
(facilement portable sur x86-32, le portage sur d'autres architectures implique une perte de vitesse importante)
Voici ma propre micro-implémentation de longue arithmétique.
Le calcul lui-même prend 10 secondes, et bien que la sortie soit sous une forme facilement imprimable (voir la
operator<<
surcharge), il faut plus de temps pour l'imprimer.la source
g++ -O2 factorial.cc -o factorial
et il obtient 3,90 = 382000 / 98000.r
augmente. Si c'est le cas, et que vous pouvez faire un plus hautr
en 10 secondes, votre score diminue.Python 3: 280000/168000
Temps d'exécution de votre programme: entre
9.87585953253
et10.3046453994
. Temps d'exécution de mon programme: environ10.35296977897559
.J'ai lu cette réponse sur cs.SE et j'ai décidé d'essayer de l'implémenter en Python. Cependant, j'ai accidentellement découvert cela
n! = (⌊n / 2⌋)! * 2**(⌊n / 2⌋) * n!!
(note:!!
c'est le double factoriel ). J'ai donc converti cela en une forme non récursive.Les commentaires montrent ma tentative pour éviter de recalculer la double factorielle, mais j'ai découvert que le stockage de chaque valeur était trop coûteux en mémoire, ce qui faisait que mon ordinateur fonctionnait encore plus lentement. Je peux améliorer cela en ne stockant que ce qui est nécessaire.
Étrangement, j'ai implémenté la multiplication droite naïve en Python 3, et elle fait mieux que votre programme:
n = 169000
en 10 secondes .:la source
Ruby 2.1
score = 1,80 = 176_000 / 98_000
EDIT: amélioré de
1,35 = 132_000 / 98_000J'ai pris des idées de l' algorithme factoriel GMP . Ce programme utilise la bibliothèque standard pour générer des nombres premiers. Ruby est un mauvais choix car la multiplication semble plus lente en Ruby qu'en Python.
Oui, mon binaire de
ruby 2.1.0p0 (2013-12-25 revision 44422) [x86_64-openbsd]
liens contre GMP. Ruby 2.1 a ajouté une fonctionnalité pour utiliser GMP pour une multiplication importante, mais il semble toujours plus lent que Python 2.7.la source
Julia - Score = 15,194
En utilisant exactement la même approche que celle du programme de référence ... c'est-à-dire
Il utilise donc réduire, l'opération de multiplication binaire de base et une plage (dans ce cas, en utilisant big (n) pour forcer le calcul à être effectué dans BigInt plutôt que Int64). De cela, je reçois
Sur mon ordinateur, avec un programme de référence exécuté avec une entrée de 154000, j'obtiens une
Time: 10.041181 sec
sortie (exécutez en utilisantpython ./test.py
, où test.py est le nom du fichier contenant le code de référence)la source
tcl, 13757
Ma réponse est de vérifier les limites de tcl.
La première ligne sert uniquement à définir un paramètre d'entrée:
Les autres sont l'algorithme lui-même:
J'ai testé mon code sur http://rextester.com/live/WEL36956 ; Si je fais n plus grand, je reçois un SIGKILL; mai n peut devenir plus grand sur un interpréteur tcl local, que je n'ai pas.
la source