python阶乘的代码_我在python中的阶乘代码怎么了

我有以下代码用于在python中计算数字的阶乘。 但我不明白为什么我得到的答案是1。

有人可以纠正我的代码吗? 我想不使用递归来计算阶乘。

1

2

3

4

5

6

7

8

9

10def factorial (n):

result =1

num = n

while n<1:

result = result * num

num = num -1

return result

factorial(5)

1

循环条件取决于n,但是您只能在循环中更改result和num。 循环将运行0次或无限次。

由于Frerich和PM 2Ring始终处于状态,因此math.factorial快得多。

@Pureferret我想我们必须在这里假设,OP的目标不仅仅是他有一些数字,而且想知道他们的阶乘是什么。

1while n < 1:

相反应该是

1while num > 1:

其他人指出了您的代码出了什么问题,但是我想指出,factorial函数确实适合于功能更强大的解决方案(如在函数编程中)。这完全避免了获得while循环的条件的问题,因为您根本没有任何循环。洞察力是n的阶乘是1..n的乘积,并且可以使用Python的reduce函数非常轻松地定义乘积。为了避免失去性能,这是我的Python 2.7解释器为您的(固定)代码提供的功能:

1

2python -m timeit -s"import original""original.factorial(10)"

1000000 loops, best of 3: 1.22 usec per loop

声明更短的版本(单线)是可能的:

1

2def factorial(n):

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

... ala,速度较慢:

1

2python -m timeit -s"import func1""func1.factorial(10)"

1000000 loops, best of 3: 1.98 usec per loop

但是,可以使用xrange代替range和operator.mul代替自定义lambda来解决:

1

2

3

4import operator

def factorial(n):

return reduce(operator.mul, xrange(1, n+1))

对我来说,这比原始代码还要快:

1

2python -m timeit -s"import func2""func2.factorial(10)"

1000000 loops, best of 3: 1.14 usec per loop

就个人而言,我会排除reduce调用以使代码更清晰(以牺牲一点点性能为代价):

1

2

3

4

5

6

7import operator

def product(it):

return reduce(operator.mul, it)

def factorial(n):

return product(xrange(1, n+1))

我喜欢这个版本,因为它速度快,而且表达明确:阶乘被定义为范围[1..n + 1 [(即,不包括n + 1)。如果尝试计算较大数字的阶乘,则性能差异会变得更加明显:

1

2python -m timeit -s"import original""original.factorial(30)"

100000 loops, best of 3: 5.25 usec per loop

1

2python -m timeit -s"import func3""func3.factorial(30)"

100000 loops, best of 3: 3.96 usec per loop

这如何回答这个问题?

@Pureferret:它没有回答问题(问题已经回答),它通过显示可以完全避免问题的替代实现扩展了现有答案(因为不需要显式的for循环)。

如果没有回答问题,您为什么回答?为什么不只是发表评论?

@Pureferret评论不能为我写的内容提供足够的空间(更不用说可读性了)。

怎么样,这不是最好的方法?

@Pureferret链接到外部内容中断和(如该特定答案所引用)" SO的主要目标之一是提供一个全面的Q&A存储库(而不仅仅是问答论坛)"。如果接受的答案的作者将他的文字扩展到我写的内容上,我会很高兴,但是只要不是这样,添加另一个需要后退的答案就是一个不错的妥协。如果让您满意,我还可以添加"将n<1更改为num>1"。 ;-)

那只是讨论链接而不是答案。所需的内容由#1:Allow external links only for backup to answers覆盖,如您的答案一样,备份接受的答案。

@FrerichRaabe,当没什么好说的人开始讨价还价时,我"享受"它

@FrerichRaabe-很棒的解释。我无法更改接受的答案,因为这不能回答我的问题。但是您的解释向我介绍了许多新概念。我支持您的解决方案。

@危险:西蒙斯的回答简短而切合实际,因此非常完美,可以接受(我自己也赞成)。的确,这里的一些答案并不能解决您的主要问题,但是它们是在尝试提高现有答案的价值。 FWIW,Ive增强了我昨天提交的答案。 :)

让我们来看看:

调用函数时设置n=5。

您告诉Python n < 1做事。

n已经大于1,它不会执行while代码。

您的代码返回result,在定义的第一行中将其设置为1。

while 5 < 1始终为false,因此返回result = 1。错了

得到它了!!这是一个愚蠢的错误。我是编程新手。

我应该学习递归。我真的对递归的概念感到困惑。或者我可以摆脱python中的循环。

您当然应该学习递归的概念。哪种方法最好取决于具体情况。

好的,然后我将开始学习它:(

正如Simon Gibbons解释的那样,您的代码具有

while n < 1:

代替

while num > 1:

因此,您拥有小于而不是大于,因此while语句中的测试将立即失败。但是,如果将其更改为while n > 1:,它将永远循环,因为您永远不会在while循环内更改n的值。

Haresh Shyara发布了您的代码的更正版本,转载于此处:

1

2

3

4

5

6def factorial(n):

result = 1

while n > 1:

result = result * n

n = n - 1

return result

请注意,此代码不会干扰将n复制到num -它仅直接使用n。这不会影响调用该函数的参数,因为

Python整数是不可变的,并且

n = n - 1实际上创建了一个名为n的新本地对象。

弗雷里希·拉贝(Frerich Raabe)的回答启发了我,我写了一个程序,以一种更加系统的方式来确定此处提供的各种解决方案的时间。我还包括了我刚刚组合在一起的math.factorial()和一个简单的for循环函数。

我已经通过定义mul = operator.mul来稍微优化了调用operator.mul的函数,但是我必须为使用reduce()的那些函数提供一个initial参数1,以使它们不会在factorial(0)上失败(应该返回1)。

我大约已从快速到慢速订购了这些功能。

我刚刚增强了该程序,使其可以轻松运行多个测试并添加新功能进行测试。而且,现在它使用函数的文档字符串打印每个函数的简要说明。并且在运行时序测试之前,它会验证每个函数是否计算出正确的值。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122#!/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 '

%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 '

'

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()

输出

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88Arg = 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提供):

... the lowest value gives a lower bound for how fast your machine can

run the given code snippet; higher values in the result vector are

typically not caused by variability in Python’s speed, but by other

processes interfering with your timing accuracy. So the min() of the

result is probably the only number you should be interested in...

是的,即使您的解决方案看起来也不错。但我无法理解这部分def factorial(n):return reduce(lambda res,val:res * val,xrange(n,0,-1),1)。您能解释一下此阶乘代码的内容吗?

@危险:火山代码与使用reduce的其他版本非常相似。您了解reduce()的作用吗?您了解lambda的作用吗?

是的,我明白reduce和lambda

@dangerous:好的,那你还不懂? xrange()有点愚蠢,但是它只是迭代从n到1的整数。

在这种情况下,我对reduce的确切应用感到困惑。 reduce接受一个函数并将其应用于每个可迭代对象。因此,这里的lambda函数将两个数字相乘。因此,如果我想计算5的阶乘,如何使用此代码实现?

@危险:对于可迭代reduce中的每个元素,该函数均传递两个值,一个是当前结果(res),另一个是可迭代(val)中的当前元素,该函数的结果由,以便可以将其传递回下一步。我之前链接的reduce文档中的示例代码说明了该过程。病态发布了一些使用for循环的代码,该循环等效于volcanos代码,但是我将其编辑为volcanos问题,因为这是他的代码Im在解释。

好的,现在我明白了。确实使用for循环发布您的解决方案:)

@危险:我原来的for循环解决方案已经在我的答案中:它的factorial1()。我不会将其发布为单独的答案,因为在所有Stack Exchange网站上都强烈建议一个人发布一个问题的多个答案。但请随时投票给这个答案。 :)但是,如果您在谈论for循环,该循环等效于火山代码,请参见他的回答。

我赞成:)

我认为速度优化不是这里的重要目标。

@jwg:当然,OP问题的主要答案是解释其逻辑出了什么问题。但是,Stack Overflow不仅仅是回答OP特定的问题,因此SO答案对将来的读者也应该是有用的。编写阶乘函数是初学者的常见任务,并且很高兴在一个地方拥有多种算法,因此人们可以进行比较和对比。

(续)如果某人想要速度,则不应使用自己的阶乘函数:他们应使用内置的math.factorial或第三者的gmpy或mpmath模块。如果他们确实需要速度,则不应该使用标准Python,而应该使用可以编译为机器代码的工具。

1

2

3

4

5

6

7

8

9def factorial(n):

result = 1

while n > 1:

result = result * n

n = n - 1

return result

print factorial(5)

120

这种回答不是很有帮助。您只是提供一个固定的代码段。请说明原始代码片段出了什么问题以及为什么您的版本有效。即使接受的答案仅包含少量代码,它还是更好的,因为它以更清晰的方式说明了问题。

(当n <1时)这在原始代码段n = 5中是错误的,因此(5 <1)如果不执行控件而不是主体部分,则返回result = 1。其次是在while循环中使用变量n并减少num变量

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

试试看,它更干净:

1

2

3

4

5def factorial( n ):

if n <= 1:

return 1;

else:

return n*factorial(n-1)

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

为什么递归方式更干净?

我不正确理解递归。那就是为什么我使用循环;)

也许这个词不干净,但我认为它更好。您使用较少的代码行,并使用普通或自然的方式来理解阶乘运算:N! = N *(N-1)! ,除非N = 1,然后N! = 1.这确实是个人观点,

递归未在Python中进行优化,并且它对递归深度有限制(尽管可以修改该限制)。最好使用递归(例如树处理)来解决一些问题,但是通常,如果您可以轻松地使用迭代算法解决问题,则最好避免递归。

第二个@ PM2Ring-即使堆栈是无限的,使用大量堆栈仍然会受到惩罚-并且没有真正的理由将其用于可能通过迭代轻松解决的问题

@volcano:确实;大量的堆栈使用量不仅会增加程序的内存使用量,还会降低其运行速度。正如我刚刚发布的时间显示的那样,递归阶乘相对较慢。

无论其价值如何,都可以对定义进行调整,以使该函数具有尾递归功能,但是可惜Python无法优化尾递归,因此即使递归定义很好地遵循了数学定义,也不可行。

谈到简短的Pythonic代码

1

2def factorial(n):

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

对于那些不了解火山代码工作原理的人,这里是一个近似的近似值:

1

2

3

4

5

6

7

8

9

10''' 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

这看起来不像发问者代码,这有什么帮助?

@Pureferret,愚蠢的理由拒绝投票-但请成为我的客人。出于好奇,您是否对本主题中提供其他解决方案的所有答案都否决了?

@ volcano-您的解决方案看起来有些不同。您能解释一下函数reduce(lambda res,val:resval,xrange(n,0,-1),1)如何工作吗?我知道lambda res,val:resval将两个数字相乘。但是我无法得到reduce(function,xrange(n,0,-1),1)背后的逻辑。你能详细说明你的答案吗?

实际上,向后范围是没有意义的-当我写它的时候并没有思考。初始值也是多余的-我不经常使用reduce,所以最初我错过了

初始值_isnt _冗余:考虑factorial(0)会发生什么。

@ PM2Ring,错过了,谢谢

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值