簡體   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