自然数的阶乘(任何大于或等于0
的数字)是该数乘以其自身的阶乘减1,其中0
的阶乘被定义为{{1} }。
例如:
1
另一种写作方式是将0! = 1
1! = 1 * 0!
2! = 2 * 1!
3! = 3 * 2!
4! = 4 * 3!
5! = 5 * 4!
与1
之间的所有自然数相乘:
n
如何用F#中的递归函数表达这个?并且应该我用递归函数做到了吗?
n!
答案 0 :(得分:23)
如何,选项1:
let rec factorial n =
match n with
| 0 | 1 -> 1
| _ -> n * factorial(n-1)
如何,选项2(尾递归,编译成循环):
let factorial n =
let rec loop i acc =
match i with
| 0 | 1 -> acc
| _ -> loop (i-1) (acc * i)
loop n 1
应该:不,请看我的回答:
While or Tail Recursion in F#, what to use when?
我提倡经常避免迭代和递归,而支持高阶函数。但是如果你刚刚开始,也许不要过多担心这个建议。 (但后来看到例如@ ChaosPandion的答案,或者例如。
let factorial n = [1..n] |> List.fold (*) 1
甚至:
let factorial n = [1..n] |> List.reduce (*) // doesn't require the 2nd parameter
答案 1 :(得分:8)
这是另一个例子:
let factorial (num:int) =
seq { for n in [1..num] -> n }
|> Seq.reduce (fun acc n -> acc * n)
这个例子可能更清楚一点:
let factorial num =
[1..num] |> Seq.fold (fun acc n -> acc * n) 1
答案 2 :(得分:5)
Brian的回答是最实用的,但这是继续传递风格的解决方案:
let rec factorial n =
let rec loopk i k =
match i with
| 0 | 1 -> k i
| _ -> loopk (i-1) (fun r -> k (i * r))
in loopk n (fun r -> r)
答案 3 :(得分:3)
我如何为此声明一个递归函数?
首先,要定义递归函数,您需要使用let rec
而不是let
(因为let
不允许您引用递归定义的函数)。
要递归地定义阶乘函数,最简单(但不是最有效)的方法是使用阶乘函数的标准数学定义。
更有效的方法是定义一个尾递归辅助函数,使用第二个参数存储到目前为止计算的结果。
答案 4 :(得分:3)
我最喜欢的递归序列的F#解决方案是......无限的尾递归序列!:
let factSeq =
let rec factSeq m n =
seq { let m = m * n
yield m
yield! factSeq m (n+1I) }
seq { yield 1I ; yield 2I ; yield! (factSeq 2I 3I) }
let factTake n = factSeq |> Seq.take n //the first n terms
let fact n = factSeq |> Seq.nth (n-1) //the nth term
我在这里使用BigIntegers,因为阶乘序列增长如此之快(继续,尝试第20,000个术语)。
我通常同意Brian的建议,即尽可能在迭代循环或递归循环(尾递归+累加器)上使用高阶函数。但我认为在这种情况下,我所展示的无限序列更灵活,因为它产生了阶乘序列的所有项,直到所需的项(factTake
),并且每个项只需要一个乘法步骤( N *(N-1))。然而,如果您想要使用折叠解决方案的前n个术语,则每个计算将独立完成,并且不会从先前的计算中受益。
答案 5 :(得分:0)
这是一个更简单的实现
let rec bfact (n):bigint =
match n with
| i when i<0 -> bigint.Zero
| 0 | 1 -> bigint(1)
| _ -> ( bfact(n-1) * bigint(n) )
并测试
bfact(50)
val bfact : n:int -> bigint
val it : bigint =
30414093201713378043612608166064768844377641568960512000000000000