что не так с моим факториальным кодом в python

У меня есть следующий код для вычисления факториала числа в python. но я не мог понять, почему я получаю ответ как 1. может ли кто-то исправить мой код. Я хочу вычислить факториал без использования рекурсии.

def factorial (n): result =1 num = n while n<1: result = result * num num = num -1 return result factorial(5) 1 

 while n < 1: 

следует вместо этого

 while num > 1: 

Другие указали, что не так с вашим кодом, но я хотел бы указать, что factorial функция действительно подходит для более функционального (как в случае функционального программирования) решения; это позволяет избежать проблемы с получением условия для цикла while вообще, потому что у вас вообще нет петли. Понимание заключается в том, что факториал n является произведением 1..n , и продукт может легко отреагировать с помощью функции reduce Python. Чтобы избежать потери производительности вне поля зрения, вот что мой интерпретатор Python 2.7 дает для вашего (фиксированного) кода:

 python -m timeit -s "import original" "original.factorial(10)" 1000000 loops, best of 3: 1.22 usec per loop 

Возможна более короткая версия (однострочный), которая более декларативная:

 def factorial(n): return reduce(lambda x,y: x*y, range(1, n+1)) 

… увы, это медленнее:

 python -m timeit -s "import func1" "func1.factorial(10)" 1000000 loops, best of 3: 1.98 usec per loop 

Однако это можно решить с помощью xrange вместо range и operator.mul вместо пользовательской лямбда:

 import operator def factorial(n): return reduce(operator.mul, xrange(1, n+1)) 

И для меня это даже быстрее, чем исходный код:

 python -m timeit -s "import func2" "func2.factorial(10)" 1000000 loops, best of 3: 1.14 usec per loop 

Лично я бы отказался от призыва на reduce чтобы сделать код еще более ясным (за счет небольшой производительности):

 import operator def product(it): return reduce(operator.mul, it) def factorial(n): return product(xrange(1, n+1)) 

Мне нравится эта версия для быстрого и для явного: факториал определяется как произведение диапазона [1..n + 1 [(т. Е. N + 1 исключается). Разница в производительности становится более очевидной, если вы попытаетесь вычислить факториал больших чисел:

 python -m timeit -s "import original" "original.factorial(30)" 100000 loops, best of 3: 5.25 usec per loop 

против

 python -m timeit -s "import func3" "func3.factorial(30)" 100000 loops, best of 3: 3.96 usec per loop 

while 5 < 1 всегда false, поэтому возвращается result = 1 . Это неверно.

Посмотрим:

  1. При вызове функции вы устанавливаете n=5 .
  2. Вы говорите Python, что при n < 1 делайте что-нибудь.
  3. n уже больше 1 , он не будет выполнять код while .
  4. Ваш код возвращает result , устанавливается в 1 в первой строке определения.

Как объяснил Саймон Гиббонс, ваш код

while n < 1:

вместо

while num > 1:

Таким образом, у вас меньше, чем вместо того, чтобы больше , поэтому тест в вашем заявлении while не срабатывает немедленно. Однако, если вы изменили его на while n > 1: он будет циклически навсегда, так как вы никогда не изменяете значение n внутри цикла while.

Haresh Shyara опубликовал исправленную версию вашего кода, воспроизведенную здесь:

 def factorial(n): result = 1 while n > 1: result = result * n n = n - 1 return result 

Обратите внимание, что этот код не требует копирования n в num – он просто использует n напрямую. Это не повлияет на аргумент, который вы вызываете функцией, потому что

  1. Целые числа на Python неизменяемы и
  2. n = n - 1 фактически создает новый локальный объект с именем n .

Я был вдохновлен ответом Фририха Раабе на то, чтобы написать программу, чтобы сделать тайминги различных решений, предлагаемых здесь более систематическим образом. Я также включил math.factorial() и простую for петля функцию, которую я просто сбрасывал.

Я оптимизировал функции, которые вызывали operator.mul немного, определяя mul = operator.mul , но я должен был предоставить initial параметр 1 для тех функций, которые используют reduce() чтобы они не терпели неудачу по factorial(0) (который должен возвращать 1).

Я приблизительно заказал функции от самого быстрого до самого медленного.

Я только что улучшил эту программу, чтобы немного упростить выполнение нескольких тестов и добавить новые функции для тестирования. Кроме того, теперь он печатает краткое описание каждой функции, используя docstring функции. И перед запуском тестов времени он проверяет, что каждая функция вычисляет правильные значения.

 #!/usr/bin/env python ''' Test and time various implementations of the factorial function From https://stackoverflow.com/q/28475637/4014959 Written by PM 2Ring 2015.02.13 ''' import operator import math from timeit import Timer factorial0 = math.factorial def factorial0a(n): ''' call math.factorial ''' return math.factorial(n) def factorial1(n): ''' for loop''' p = 1 for i in xrange(2, n+1): p *= i return p mul = operator.mul def product(it): return reduce(mul, it, 1) def factorial2(n): ''' reduce with op.mul ''' return reduce(mul, xrange(1, n+1), 1) def factorial3(n): ''' call product() ''' return product(xrange(1, n+1)) def factorial4(n): ''' while loop ''' result = 1 while n > 1: result = result * n n = n - 1 return result def factorial4a(n): ''' while loop with assignment operators ''' result = 1 while n > 1: result *= n n -= 1 return result def factorial5(n): ''' recursive ''' if n <= 1: return 1; else: return n*factorial5(n-1) def factorial6(n): ''' reduce with lambda ''' return reduce(lambda res, val: res*val, xrange(n, 0, -1), 1) funcs = ( factorial0, factorial0a, factorial1, factorial2, factorial3, factorial4, factorial4a, factorial5, factorial6, ) def verify(n): ''' Check that each function calculates the same result as math.factorial ''' r = xrange(n) fac = [factorial0(i) for i in r] rc = True for func in funcs[1:]: for i in r: v = func(i) if v != fac[i]: print 'Error: %s(%d) returns %d instead of %d' % (func.func_name, i, v, fac[i]) rc = False return rc def time_test(arg=10, loops=100000, reps=3): ''' Print timing stats for all the factorial functions ''' print 'Arg = %d, Loops = %d, Repetitions = %d' % (arg, loops, reps) for func in funcs: #Get function name and docstring try: fname = func.func_name fdoc = func.__doc__ except AttributeError: #Math.factorial has no name, and we can't modify its docstring fname = 'factorial0' fdoc = ' math.factorial itself ' print '\n%s:%s' % (fname, fdoc) t = Timer('%s(%d)' % (fname, arg), 'from __main__ import %s' % fname) r = t.repeat(reps, loops) r.sort() print r print '\n' def main(): if not verify(100): exit(1) time_test(arg=5, loops=500000, reps=4) time_test(arg=10, loops=200000, reps=4) time_test(arg=50, loops=100000, reps=4) if __name__ == '__main__': main() 

вывод

 Arg = 5, Loops = 500000, Repetitions = 4 factorial0: math.factorial itself [0.30838108062744141, 0.3119349479675293, 0.31210899353027344, 0.32166290283203125] factorial0a: call math.factorial [0.62141299247741699, 0.62747406959533691, 0.63309717178344727, 0.66500306129455566] factorial1: for loop [1.4656128883361816, 1.476855993270874, 1.4897668361663818, 1.5052030086517334] factorial2: reduce with op.mul [1.5841941833496094, 1.5868480205535889, 1.6007061004638672, 1.6253509521484375] factorial3: call product() [1.8745129108428955, 1.8750350475311279, 1.8822829723358154, 1.9097139835357666] factorial4: while loop [1.1264691352844238, 1.1348199844360352, 1.1348659992218018, 1.178135871887207] factorial4a: while loop with assignment operators [1.1867551803588867, 1.1881229877471924, 1.1893219947814941, 1.2020411491394043] factorial5: recursive [1.9756920337677002, 1.9862890243530273, 1.9910380840301514, 2.0284240245819092] factorial6: reduce with lambda [2.8342490196228027, 2.8369259834289551, 2.8390510082244873, 2.8969988822937012] Arg = 10, Loops = 200000, Repetitions = 4 factorial0: math.factorial itself [0.24756813049316406, 0.24919605255126953, 0.26395106315612793, 0.28582406044006348] factorial0a: call math.factorial [0.3732609748840332, 0.37482404708862305, 0.37592387199401855, 0.38288402557373047] factorial1: for loop [0.88677501678466797, 0.89632201194763184, 0.89948821067810059, 0.90272784233093262] factorial2: reduce with op.mul [0.89040708541870117, 0.89259791374206543, 0.89863204956054688, 0.90652203559875488] factorial3: call product() [1.0093960762023926, 1.031667947769165, 1.2325050830841064, 1.7492170333862305] factorial4: while loop [0.93423891067504883, 0.93978404998779297, 0.94000387191772461, 0.95153117179870605] factorial4a: while loop with assignment operators [0.97296595573425293, 0.97462797164916992, 0.98288702964782715, 1.0095341205596924] factorial5: recursive [1.6726200580596924, 1.6786048412322998, 1.691572904586792, 1.6946439743041992] factorial6: reduce with lambda [1.8484599590301514, 1.8502249717712402, 1.8615908622741699, 1.9228360652923584] Arg = 50, Loops = 100000, Repetitions = 4 factorial0: math.factorial itself [1.6450450420379639, 1.6641650199890137, 1.6790158748626709, 1.7192811965942383] factorial0a: call math.factorial [1.7563199996948242, 2.0039281845092773, 2.1530590057373047, 2.3621060848236084] factorial1: for loop [2.7895750999450684, 2.8117640018463135, 2.8381040096282959, 3.0019519329071045] factorial2: reduce with op.mul [2.4697721004486084, 2.4750289916992188, 2.4813871383666992, 2.5051541328430176] factorial3: call product() [2.4983038902282715, 2.4994339942932129, 2.5271379947662354, 2.5356400012969971] factorial4: while loop [3.6446011066436768, 3.650169849395752, 3.6579680442810059, 3.7304909229278564] factorial4a: while loop with assignment operators [3.7421870231628418, 3.7477319240570068, 3.7655398845672607, 3.7749569416046143] factorial5: recursive [5.523845911026001, 5.5555410385131836, 5.5760359764099121, 6.2132260799407959] factorial6: reduce with lambda [4.9984982013702393, 5.0106558799743652, 5.0363597869873047, 5.0808289051055908] 

Как и во всех результатах timeit , самые быстрые записи в каждом списке являются значимыми, более медленные должны игнорироваться.

Из документов timeit (любезно предоставлено Ffisegydd ):

… самое низкое значение дает нижнюю оценку того, насколько быстро ваш компьютер может запустить данный фрагмент кода; более высокие значения в векторе результата обычно не вызваны изменчивостью скорости Python, а другими процессами, мешающими вашей точности времени. Таким образом, min() результата, вероятно, является единственным номером, который вам интересен …

Ваш код не будет вводить сам цикл while. Измените его с n<1 на n>1 . Если, например, поиск факториала 5, n <1 будет рассматриваться как 5 <1, что неверно.

 def factorial(n): result = 1 while n > 1: result = result * n n = n - 1 return result print factorial(5) 120 

Попробуйте, это чище:

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

Это рекурсивный способ решения проблемы.

Говоря о коротком коде Pythonic

 def factorial(n): return reduce(lambda res, val: res*val, xrange(n, 0, -1), 1) 

Для тех, кто не понимает, как работает код вулкана, вот приблизительное приближение:

 ''' Equivalent code by PM 2Ring ''' def f(res, val): return res * val def factorial(n): res = 1 for val in xrange(n, 0, -1): res = f(res, val) return res