Impossibile eseguire una funzione fattoriale in Python
Domanda
Il mio codice
import sys
number=int(sys.argv[1])
if number == 0
fact=1
else
fact=number
for (x=1; x<number; x++)
fact*=x; // mistake probably here
print fact
Ottengo l'errore
File "factorial.py", line 5
if number == 0
^
SyntaxError: invalid syntax
Come puoi fare una funzione fattoriale in Python?
Soluzione
Ecco il tuo codice, corretto e funzionante:
import sys
number = int(sys.argv[1])
fact = 1
for x in range(1, number+1):
fact *= x
print fact
(Lo zero fattoriale è uno, per chiunque non lo sapesse, ho dovuto cercarlo. Cool
Sono necessari due punti dopo se
, else
, per
, ecc. e il modo in cui per
funziona Python è diverso da C.
Altri suggerimenti
La riga su cui si trova il tuo errore dovrebbe essere letta
if number == 0:
Nota i due punti alla fine.
Inoltre, dovrai aggiungere gli stessi due punti dopo l'altro e il per. I due punti funzionano in modo simile a {} in altre lingue.
Infine, non è così che i loop funzionano in Python. Il codice che si desidera utilizzare tale elenco sarebbe
for x in range(1,number):
Che avrebbe lo stesso effetto di quello che hai scritto, se lo mettessi in un linguaggio in stile C.
EDIT: Oops, il ciclo for che ho dato era sbagliato, avrebbe incluso 0. Ho aggiornato il codice per correggere questo.
Capisco che probabilmente stai cercando di implementarlo da solo per motivi educativi.
Tuttavia, in caso contrario, raccomando di utilizzare la funzione fattoriale integrata dei moduli math
(nota: richiede python 2.6 o successivo):
>>> import math
>>> math.factorial(5)
120
Questo modulo è scritto in C e, come tale, sarà molto più veloce di scriverlo in Python. (anche se, se non stai calcolando fattoriali di grandi dimensioni, non sarà davvero troppo lento in entrambi i modi).
Il motivo per cui la funzione fact (n) di Mark Rushakoff era molto più efficiente è che ha perso la funzione di riduzione (). Quindi non ha mai effettivamente effettuato il calcolo.
Corretto, legge (e ottengo):
import operator, timeit, math
#
def fact1(n): return reduce(lambda x,y: x*y, range(1,n+1),1)
def fact1x(n): return reduce(lambda x,y: x*y, xrange(1,n+1),1)
def fact2(n): return reduce(operator.mul , range(1,n+1),1)
def fact2x(n): return reduce(operator.mul , xrange(1,n+1),1)
#
def factorialtimer():
for myfunc in [ "fact1", "fact1x", "fact2", "fact2x" ]:
mytimer = timeit.Timer(myfunc+"(1500)", "from __main__ import "+myfunc)
print("{0:15} : {1:2.6f}".format(myfunc, mytimer.timeit(number=1000)))
mytimer = timeit.Timer("factorial(1500)", "from math import factorial")
print("{0:15} : {1:2.6f}".format("math.factorial", mytimer.timeit(number=1000)))
Output risultante per 1500 !, 1000x:
fact1 : 3.537624
fact1x : 4.448408
fact2 : 4.390820
fact2x : 4.333070
math.factorial : 4.091470
E sì, ho verificato che producono tutti lo stesso valore! Non riesco a capire perché la lambda xrange sia molto peggio della gamma lambda. Hmmm. Versione: PythonWin 2.6.2 (r262: 71605, 14 aprile 2009, 22:40:02) [MSC v.1500 32 bit (Intel)] su win32.
Hmm ... nel rieseguirlo ottengo qualcosa di più credibile
fact1 : 7.771696
fact1x : 7.799568
fact2 : 7.056820
fact2x : 7.247851
math.factorial : 6.875827
E su Python 2.6.5 (r265: 79063, 12 giugno 2010, 17:07:01) [GCC 4.3.4 20090804 (versione) 1] su cygwin:
fact1 : 6.547000
fact1x : 6.411000
fact2 : 6.068000
fact2x : 6.246000
math.factorial : 6.276000
Tutto davvero nel rumore, vero?
Ecco un fattoriale funzionale, che hai quasi chiesto:
>>> def fact(n): return reduce (lambda x,y: x*y, range(1,n+1))
...
>>> fact(5)
120
Non funziona per i fatti (0), ma puoi preoccupartene al di fuori dell'ambito di fact
:)
Masi ha chiesto se lo stile funzionale è più efficiente dell'implementazione di Richie. Secondo il mio rapido benchmark (e con mia sorpresa!) Sì, il mio è più veloce. Ma ci sono un paio di cose che possiamo fare per cambiare.
Innanzitutto, possiamo sostituire lambda x, y: x * y
con operator.mul
come suggerito in un altro commento. L'operatore lambda
di Python ha un overhead non insignificante. In secondo luogo, possiamo sostituire xrange
con range
. xrange
dovrebbe funzionare nello spazio lineare, restituendo i numeri se necessario, mentre range
crea l'intero elenco in una sola volta. (Nota quindi che quasi certamente devi usare xrange
per un intervallo di numeri eccessivamente ampio)
Quindi la nuova definizione diventa:
>>> import operator
>>> def fact2(n): return reduce(operator.mul, xrange(1,n+1))
...
>>> fact2(5)
120
Con mia sorpresa, ciò ha comportato prestazioni più lente. Ecco i benchmark Q & amp; D:
>>> def fact(n): return (lambda x,y: x*y, range(1,n+1))
...
>>> t1 = Timer("fact(500)", "from __main__ import fact")
>>> print t1.timeit(number = 500)
0.00656795501709
>>> def fact2(n): return reduce(operator.mul, xrange(1,n+1))
...
>>> t2 = Timer("fact2(500)", "from __main__ import fact2")
>>> print t2.timeit(number = 500)
0.35856294632
>>> def fact3(n): return reduce(operator.mul, range(1,n+1))
...
>>> t3 = Timer("fact3(500)", "from __main__ import fact3")
>>> print t3.timeit(number = 500)
0.354646205902
>>> def fact4(n): return reduce(lambda x,y: x*y, xrange(1,n+1))
...
>>> t4 = Timer("fact4(500)", "from __main__ import fact4")
>>> print t4.timeit(number = 500)
0.479015111923
>>> def fact5(n):
... x = 1
... for i in range(1, n+1):
... x *= i
... return x
...
>>> t5 = Timer("fact5(500)", "from __main__ import fact5")
>>> print t5.timeit(number = 500)
0.388549804688
Ecco la mia versione di Python nel caso in cui qualcuno volesse fare un controllo incrociato dei miei risultati:
Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41)
[GCC 4.3.3] on linux2
davvero, l'opzione più semplice sarebbe:
def factorial(n):
x = n
for j in range(1, n):
x = j*x
return x
sì, in qualche modo, funziona.
Come hai potuto non pensarci? Non lo so.
Un ciclo per
e un moltiplicatore, davvero la semplicità è il modo migliore di procedere, giusto?
EDIT: Oh, aspetta, stiamo lavorando per il modo più efficace di cpu? ohhhh .....