我正在做一些作业,我们应该在 F# 中创建一个组合函数。我已经得到了阶乘函数,但是一旦我得到一个大数字来使用阶乘,它似乎就会溢出。(比方说 20)我知道我可以使用 int64 或 float,但这会改变代码上的所有输入。我应该使用什么数据类型?
let rec Fact (a:int)=
if (a = 0) then 1 else a*Fact(a-1);;
let combo (n:int) (k:int)=
if (n = 0) then 0 else (Fact n)/((Fact k)*(Fact (n-k)));;
Run Code Online (Sandbox Code Playgroud)
在现在的代码中,当我执行组合 20 5;; 时 它给了我 2147。这显然是错误的答案。我查看了阶乘函数,当我将 20 放入其中时,它给出了一个很大的负数。任何帮助将非常感激。提前致谢。
首先,如果您想避免意外,您可以打开Checked文件顶部的模块。这将重新定义数字运算符,以便它们执行溢出检查 - 并且您将得到异常而不是意外的数字:
open Microsoft.FSharp.Core.Operators.Checked
Run Code Online (Sandbox Code Playgroud)
正如 Fyodor 在评论中指出的那样,您无法将 20 的阶乘放入其中int,而您需要int64。但是,您的combo函数随后执行除法,这将使 的结果combo 20 5足够小以适合int。
一种选择是更改Fact为 use int64,但保留combo为接受并返回整数的函数 - 您需要int64在调用之前将它们转换为 ,然后在执行除法后Fact返回:int
let rec Fact (a:int64) =
if (a = 0L) then 1L else a * Fact(a-1L)
let combo (n:int) (k:int) =
if (n = 0) then 0 else int (Fact (int64 n) / (Fact (int64 k) * Fact (int64 (n-k))))
Run Code Online (Sandbox Code Playgroud)
现在你可以打电话combo 20 5,你就会得到15504结果。
编辑:正如 @pswg 在另一个答案中指出的那样,int64也非常有限,因此您需要BigInteger更大的阶乘。但是,相同的方法应该适用于您BigInteger。您可以将该函数保留为通过从to转换回combo返回的函数。intBigIntegerint