繁体   English   中英

f#中的int溢出

[英]Overflow of an int in f#

我正在做一些作业,我们应该在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)));;

在代码上,当我组合20 5 ;; 它给了我2147。这显然是错误的答案。 我看了阶乘函数,当我在其中放20时,它给了我很大的负数。 任何帮助将非常感激。 提前致谢。

首先,如果要避免意外,可以打开文件顶部的Checked模块。 这将重新定义数值运算符,以便它们执行溢出检查-您将得到异常而不是意外的数字:

open Microsoft.FSharp.Core.Operators.Checked

正如Fyodor在评论中指出的那样,您不能将int 20的阶乘设置为int并且需要int64 但是,然后,您的combo函数执行除法运算,这将使combo 20 5的结果足够小以适合int

一种选择是将Fact更改为使用int64 ,但将combo用作接受并返回整数的函数-您需要在调用Fact之前将它们转换为int64 ,然后在执行除法操作后将其转换为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))))

现在您可以调用combo 20 5 ,结果为15504

编辑:正如在另一个答案中@pswg所指出的那样, int64也非常有限,因此对于较大的阶乘,您将需要BigInteger 但是,使用BigInteger可以使用相同的方法。 你可以保持combo功能作为一个返回函数int通过转换从后面BigIntegerint

您根本无法使用32位整数( int )来做到这一点。 64位整数最多可以使您达到20! ,但将在21!失败21! 数字变得太大,太快。 要进一步发展,您将需要使用System.Numerics.BigInteger (在F#中为bigint缩写)。

该参数可以合理地保留为int ,但是您需要返回一个bigint

let rec Fact (n : int) = 
    if n = 0 then bigint.One else (bigint n) * Fact (n - 1)

或者更习惯一些:

let rec Fact = function | 0 -> bigint.One | n -> (bigint n) * Fact (n - 1)

现在,在您的Combo函数中,您将需要在内部对所有数学使用这些bigint (很幸运,在这种情况下,只需要整数除法)。

let Combo (n : int) (k : int) =
    if n = 0 then bigint.Zero else (Fact n) / ((Fact k) * (Fact (n - k)))

如果您真的想让Combo返回一个int ,则可以在此处进行转换:

let Combo (n : int) (k : int) =
    if n = 0 then 0 else (Fact n) / ((Fact k) * (Fact (n - k))) |> int

例子:

Combo 20 5 // --> 15504
Combo 99 5 // --> 71523144 (would break if you used int64)

编辑 :通过重新考虑Combo的实现,您可以从中获得一些重大的性能改进。 有关实现的基础,请参见Math.SE上的以下问题:

let ComboFast (n : int) (k : int) =
    let rec Combo_r (n : int) = function 
        | 0 -> bigint.One 
        | k -> (bigint n) * (Combo_r (n - 1) (k - 1)) / (bigint k)
    Combo_r n (if (2 * k) > n then n - k else k)

快速测试平台显示,这是显著比快Fact之上为基础的版本:

Function             Avg. Time (ms)
Combo 99 5            30.12570 
ComboFast 99 5         0.72364

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM