J'ai résolu le problème 10 de Project Euler avec le code suivant, qui fonctionne par force brute:
def isPrime(n):
for x in range(2, int(n**0.5)+1):
if n % x == 0:
return False
return True
def primeList(n):
primes = []
for i in range(2,n):
if isPrime(i):
primes.append(i)
return primes
def sumPrimes(primelist):
prime_sum = sum(primelist)
return prime_sum
print (sumPrimes(primeList(2000000)))
Les trois fonctions fonctionnent comme suit:
J'ai ensuite écrit une nouvelle fonction, primeListRec , qui fait exactement la même chose que primeList , pour m'aider à mieux comprendre la récursivité:
def primeListRec(i, n):
primes = []
#print i
if (i != n):
primes.extend(primeListRec(i+1,n))
if (isPrime(i)):
primes.append(i)
return primes
return primes
La fonction récursive ci-dessus a fonctionné, mais seulement pour de très petites valeurs, comme '500'. La fonction a provoqué le blocage de mon programme lorsque j'ai mis «1000». Et quand j'ai mis une valeur comme '2000', Python m'a donné ceci:
RuntimeError: profondeur maximale de récursivité dépassée .
Qu'est-ce que j'ai mal fait avec ma fonction récursive? Ou existe-t-il un moyen spécifique d'éviter une limite de récursivité?
La récursivité n’est pas la façon la plus idiomatique de faire des choses en Python, car elle n’a pas tail récursivité optimisation, rendant ainsi peu pratique l’utilisation de la récursivité en remplacement de récursif, cela n’aiderait pas de toute façon). En gros, cela signifie que vous ne devriez pas l'utiliser pour des choses dont la complexité est supérieure à linéaire si vous vous attendez à ce que vos entrées soient volumineuses. ).
Si vous voulez essayer cette approche, utilisez un langage plus adapté à la programmation fonctionnelle, tel que LISP, Scheme, Haskell, OCaml, etc. ou essayez Stackless Python, qui a des limites plus larges dans l’utilisation de la pile et qui a également une optimisation de la récursion de la queue :-)
À propos, un équivalent de votre fonction récursif pourrait être:
def primeList(n, i=2, acc=None):
return i > n and (acc or []) or primeList(n, i+1, (acc or []) + (isPrime(i) and [i] or []))
Un autre "à propos", vous ne devriez pas construire de liste si vous l'utilisez simplement pour additionner les valeurs ... La façon pythonique de résoudre le 10ème problème de Project Euler est la suivante:
print sum(n for n in xrange(2, 2000001) if all(n % i for i in xrange(2, int(n**0.5)+1)))
(OK, peut-être que le fendre en plusieurs lignes serait encore plus pythonique, mais j'adore les doublures ^ _ ^)
Comme déjà dit, dans les langues qui ne peuvent pas traiter les piles profondes, il vaut mieux adopter une approche itérative. Dans votre cas, en particulier, il est préférable de changer l'algorithme utilisé. Je suggère d'utiliser le Sieve of Eratosthenes pour trouver la liste des nombres premiers. Ce sera plus rapide que votre programme actuel.
Eh bien, je ne suis pas un expert en python, mais je suppose que vous avez atteint la limite pile . C’est le problème de la récursion. C’est génial quand on n’a pas à récidiver très souvent, mais nul quand le nombre de récursions devient modérément élevé.
L'alternative idéale consiste à réécrire votre algorithme pour utiliser l'itération à la place.
Edit: En fait, après avoir examiné votre erreur spécifique de près, vous pouvez la surmonter en modifiant sys.getrecursionlimit . Cela ne vous mènera que jusqu'à présent si. Finalement, vous obtiendrez une exception stackoverflow qui me ramènera à mon point d'origine.
Vous parcourez n nombres et récursez à chaque étape. Par conséquent, la limite de récursivité de Python définit votre nombre maximal d'entrées. C'est évidemment indésirable. Surtout parce que les problèmes d'Euler concernent généralement de très grands nombres.