Funkcja silni w Pythonie

135

Jak mam obliczyć silnię liczby całkowitej w Pythonie?

Nir Levy
źródło

Odpowiedzi:

191

Najłatwiejszym sposobem jest użycie math.factorial(dostępne w Pythonie 2.6 i nowszych):

import math
math.factorial(1000)

Jeśli chcesz / musisz napisać to sam, możesz zastosować podejście iteracyjne:

def factorial(n):
    fact = 1
    for num in range(2, n + 1):
        fact *= num
    return fact

lub podejście rekurencyjne :

def factorial(n):
    if n < 2:
        return 1
    else:
        return n * factorial(n-1)

Zwróć uwagę, że funkcja silnia jest zdefiniowana tylko dla dodatnich liczb całkowitych, więc powinieneś również sprawdzić to n >= 0i to isinstance(n, int). Jeśli tak nie jest, podbij odpowiednio a ValueErrorlub a TypeError. math.factorialzajmie się tym za Ciebie.

schnaader
źródło
2
Nie rozumiem, jak możesz używać factorialtej factorialfunkcji. Jak możesz użyć tej samej funkcji w ramach funkcji, którą obecnie definiujesz? Jestem nowy w Pythonie, więc po prostu próbuję zrozumieć.
J82
8
@ J82: Pojęcie użyte tutaj nazywa się rekurencją ( en.wikipedia.org/wiki/Recursion_(computer_science) ) - funkcja wywołująca samą siebie jest w porządku i często przydatna.
schnaader
Funkcja rekurencyjna podniesie a RecursionErrordla dowolnej liczby większej niż 998 (spróbuj factorial(999)), chyba że zwiększysz limit rekursji w Pythonie
Boris
114

W Pythonie 2.6 i nowszych wypróbuj:

import math
math.factorial(n)
Joril
źródło
Począwszy od Pythona 3.9 , przekazanie a floatdo tej funkcji spowoduje podniesienie DeprecationWarning. Jeśli chcesz to zrobić, musisz przekonwertować nna intjawnie:, math.factorial(int(n))co spowoduje odrzucenie wszystkiego po przecinku, więc możesz to sprawdzićn.is_integer()
Boris
25

Nie jest to konieczne, ponieważ jest to taki stary wątek. Ale zrobiłem tutaj, to inny sposób obliczenia silni liczby całkowitej za pomocą pętli while.

def factorial(n):
    num = 1
    while n >= 1:
        num = num * n
        n = n - 1
    return num
ciziar
źródło
4
silnia (-1) zwróci 1, powinna podnieść wartość ValueError lub coś w tym rodzaju.
f.rodrigues
Ta funkcja da niepoprawne wyniki, jeśli przekażesz zmiennoprzecinkowy z liczbami po przecinku.
Boris
Dzięki tej funkcji chcę wydrukować silnię pierwszych czterech liczb całkowitych. Kiedy zamieniam num = num * npozycję wiersza z n = n - 1i uruchamiam to for i in range(1, 5): print('Factorial of', i, 'is', factorial(i))Dla każdego silniowego, wynik wynosi 0. Chciałbym poznać uzasadnienie, dlaczego num = num * nmusi być pierwsze. Dzięki!!
18

Istniejące rozwiązanie

Najkrótszym i prawdopodobnie najszybszym rozwiązaniem jest:

from math import factorial
print factorial(1000)

Budowanie własnego

Możesz także zbudować własne rozwiązanie. Ogólnie masz dwa podejścia. Najbardziej mi odpowiada:

from itertools import imap
def factorial(x):
    return reduce(long.__mul__, imap(long, xrange(1, x + 1)))

print factorial(1000)

(działa również dla większych liczb, gdy wynik stanie się long)

Drugim sposobem osiągnięcia tego samego jest:

def factorial(x):
    result = 1
    for i in xrange(2, x + 1):
        result *= i
    return result

print factorial(1000)
Tadeck
źródło
5

Jeśli używasz Python2.5 lub starszego, spróbuj

from operator import mul
def factorial(n):
    return reduce(mul, range(1,n+1))

w przypadku nowszego Pythona w module matematycznym występuje silnia, jak podano w innych odpowiedziach tutaj

John La Rooy
źródło
To jest odpowiedź tylko w Pythonie 2, reducezostała usunięta z Pythona 3.
Boris
@Boris, w Pythonie3 wystarczy dodaćfrom functools import reduce
John La Rooy
Został usunięty z jakiegoś powodu, nie powinieneś go używać artima.com/weblogs/viewpost.jsp?thread=98196
Boris
5
def fact(n):
    f = 1
    for i in range(1, n + 1):
        f *= i
    return f
Jordania
źródło
4

Używając for-loop, licząc wstecz od n:

def factorial(n):
    base = 1
    for i in range(n, 0, -1):
        base = base * i
    print(base)
rahulm
źródło
3

Ze względu na wydajność nie używaj rekursji. To byłoby katastrofalne.

def fact(n, total=1):
    while True:
        if n == 1:
            return total
        n, total = n - 1, total * n

Sprawdź wyniki pracy

cProfile.run('fact(126000)')

4 function calls in 5.164 seconds

Korzystanie ze stosu jest wygodne (podobnie jak wywołanie rekurencyjne), ale ma swoją cenę: przechowywanie szczegółowych informacji może zająć dużo pamięci.

Jeśli stos jest wysoki, oznacza to, że komputer przechowuje wiele informacji o wywołaniach funkcji.

Metoda zajmuje tylko stałą pamięć (podobnie jak iteracja).

Lub używając pętli for

def fact(n):
    result = 1
    for i in range(2, n + 1):
        result *= i
    return result

Sprawdź wyniki pracy

cProfile.run('fact(126000)')

4 function calls in 4.708 seconds

Lub używając matematyki wbudowanej

def fact(n):
    return math.factorial(n)

Sprawdź wyniki pracy

cProfile.run('fact(126000)')

5 function calls in 0.272 seconds
binbjz
źródło
1
Myślę, że ta pętla while wygląda trochę czyściej <! - language: python -> def fact (n): ret = 1 while n> 1: n, ret = n - 1, ret * n return ret
edilio
1
def factorial(n):
    result = 1
    i = n * (n -1)
    while n >= 1:
        result = result * n
        n = n - 1
    return result

print (factorial(10)) #prints 3628800

źródło
1

Oto moja próba

>>> import math
>>> def factorial_verbose(number):
...     for i in range(number):
...             yield f'{i + 1} x '
...
>>> res = ''.join([x for x in factorial_verbose(5)])
>>> res = ' '.join([res[:len(res)-3], '=', str(math.factorial(5))])
>>> res
'1 x 2 x 3 x 4 x 5 = 120'
Pedro Rodrigues
źródło
@Nir Levy, co za fajna rzecz
Pedro Rodrigues
1

Działa również jedna linia, szybkie i duże liczby:

#use python3.6.x for f-string
fact = lambda x: globals()["x"] if exec(f'x=1\nfor i in range(1, {x+1}):\n\tx*=i', globals()) is None else None
Jundullah
źródło
0

Wiem, że na to odpowiedziano, ale oto inna metoda ze zrozumieniem listy z odwróconym zakresem, dzięki czemu zakres jest łatwiejszy do odczytania i bardziej zwarty:

    #   1. Ensure input number is an integer by attempting to cast value to int
    #       1a. To accomplish, we attempt to cast the input value to int() type and catch the TypeError/ValueError 
    #           if the conversion cannot happen because the value type is incorrect
    #   2. Create a list of all numbers from n to 1 to then be multiplied against each other 
    #       using list comprehension and range loop in reverse order from highest number to smallest.
    #   3. Use reduce to walk the list of integers and multiply each against the next.
    #       3a. Here, reduce will call the registered lambda function for each element in the list.
    #           Reduce will execute lambda for the first 2 elements in the list, then the product is
    #           multiplied by the next element in the list, and so-on, until the list ends.

    try :
        num = int( num )
        return reduce( lambda x, y: x * y, [n for n in range(num, 0, -1)] )

    except ( TypeError, ValueError ) :
        raise InvalidInputException ( "Input must be an integer, greater than 0!" )

Możesz zobaczyć pełną wersję kodu w tym streszczeniu: https://gist.github.com/sadmicrowave/d4fbefc124eb69027d7a3131526e8c06

smutna kuchenka mikrofalowa
źródło
1
Nie ma potrzeby używania [n for n in range(num, 0, -1)], rangejest już iterowalne.
Mark Mishyn
0

Innym sposobem jest użycie np.prodpokazanego poniżej:

def factorial(n):
    if n == 0:
        return 1
    else:
         return np.prod(np.arange(1,n+1))
Sarah
źródło
0

Silnia dodatniej liczby całkowitej n, oznaczonej przez n!, Jest iloczynem wszystkich dodatnich liczb całkowitych mniejszych lub równych n.

Formuła :n! = n * (n-1) * (n-2) * (n-3) * (n-4) * ....... * 1

Istnieje kilka metod wyszukiwania silni w Pythonie przy użyciu wbudowanej funkcji / biblioteki itp. Tutaj utworzyłem funkcję zdefiniowaną przez użytkownika w odniesieniu do podstawowej definicji silni.

def factorial(n):
    fact = 1
    for i in range(1,n+1):
        fact = fact * i
    return(fact)

print(factorial(4))

Możemy również zaimplementować funkcję silni za pomocą recursivetechniki, jak pokazano poniżej. Ale ta metoda jest skuteczna tylko w przypadku małych wartości całkowitych. Ponieważ w rekurencji funkcja jest wywoływana wielokrotnie i wymaga miejsca w pamięci do utrzymania stosu, co nie jest wydajnym ani zoptymalizowanym podejściem do dużych wartości całkowitych w celu znalezienia silni.

def factorial(n):
    if n == 1:
        return 1
    else:
        return n * factorial(n-1)

print(factorial(4))
Usman
źródło
0
def factorial(n):
mul = 1
for i in range( 1, n + 1):
    mul *= i
print(factorial(6))
Jitendra Bhalothia
źródło
Kolejnym pytaniem, które należy zadać, jest to, co to dodaje do pozostałych 17 odpowiedzi.
pppery
Ta odpowiedź jest duplikatem tej istniejącej odpowiedzi: stackoverflow.com/a/5136481
karel
0

W poniższym kodzie wprowadzam liczbę, której silnię chcę obliczyć, a następnie mnożę -> liczbę, której silnię chcemy obliczyć z liczbami zaczynającymi się od 1,2, ...., (liczba, której silnia Chcę obliczyć -1)

    f = int(input("Enter a number whose factorial you want to calculate = "))#Number 
                                           #whose factorial I want to calculate                              
for i in range(1,f): #assume I have taken f as 5
    f=f*i # In 1st iteration f=5*1 => 5 , in second iteration f = 5*2 => 10, 3rd 
          #iteration f = 10*3 =>30, 4th iteration f = 30*4 =>120  
print(f) #It will print the updated value of "f" i.e 120
Rajat
źródło