我在python中的factorial代码出了什么问题

时间:2015-02-12 10:55:25

标签: python python-2.7

我有以下代码用于计算python中数字的阶乘。但我无法理解为什么我得到答案为1。 可以有人纠正我的代码。我想在不使用递归的情况下计算阶乘。

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

    factorial(5)
    1

9 个答案:

答案 0 :(得分:9)

while n < 1:

应该是

while num > 1:

答案 1 :(得分:6)

其他人指出你的代码有什么问题,但是我想指出一个factorial函数真正适用于更具功能性(如:函数式编程)的解决方案;这样可以避免完全获得while循环条件的问题,因为您根本没有任何循环。我们的洞察力是n的阶乘是1..n的乘积,使用Python的reduce函数可以很容易地定义产品。为了避免失去性能,这是我的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代替rangeoperator.mul代替自定义lambda可以解决此问题:

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

VS

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

答案 2 :(得分:4)

while 5 < 1始终为false,因此会返回result = 1。那是错的。

答案 3 :(得分:4)

让我们看看:

  1. 调用该函数时设置n=5
  2. 你告诉Python,n < 1做事情。
  3. n已经大于1,它不会执行while代码。
  4. 您的代码返回result,在定义的第一行设置为1

答案 4 :(得分:3)

Simon Gibbons解释说,你的代码已经

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的新本地对象。

  3. 我受到Frerich Raabe的启发,他的答案是编写一个程序,以更系统的方式完成此处提供的各种解决方案的时间安排。我还包括math.factorial()和一个简单的基于for循环的函数,我只是把它放在一起。

    我已经通过定义operator.mul优化了稍微调用mul = operator.mul的函数,但我必须为使用{{1}的函数提供initial参数1这样他们就不会在reduce()上失败(应该返回1)。

    我大致订购了从最快到最慢的功能。

    我刚刚增强了这个程序,使其更容易运行多个测试并添加新功能进行测试。此外,它现在使用函数的docstring打印每个函数的简短描述。在运行时序测试之前,它会验证每个函数是否计算出正确的值。

    factorial(0)

    <强>输出

    #!/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 docs(由Ffisegydd提供):

      

    ...最低值给出了机器速度的下限   运行给定的代码片段;结果向量中的值越高   通常不是由Python的速度变化引起的,而是由其他人引起的   过程干扰您的计时准确性。所以timeit   结果可能是你应该感兴趣的唯一数字...

答案 5 :(得分:1)

您的代码不会进入while循环本身。将其从n<1更改为n>1。例如,如果找到5的阶乘,n&lt; 1将被视为5 <1,这是错误的。

答案 6 :(得分:1)

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

print factorial(5)
120

答案 7 :(得分:0)

试试这个,它更干净:

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

这是一种解决问题的递归方法。

答案 8 :(得分:-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