f#sum一个Int32抛出的列表算术运算导致溢出

时间:2012-05-24 10:16:17

标签: .net f#

我正在尝试将所有素数的总和从0到2 000 000

这是我的代码:

let getPrimesUpTo (x : System.Int32) =
    let upperBound = Convert.ToInt32(Math.Sqrt(Convert.ToDouble(x)))

    let allNumbers = ref [1..x] in    
    for div = 2 to upperBound do allNumbers := List.filter (fun num -> (num % div <> 0 || div >= num)) !allNumbers    
    allNumbers

let sop = 
    let nums = !(getPrimesUpTo 2000000)
    List.sum nums

当我运行它时,我得到:“算术运算导致溢出”

如果我不做List.sum,我会得到素数列表

2 个答案:

答案 0 :(得分:3)

据推测,List.sum将尝试将值加总为Int32值...并且可能是2,000,000的素数之和大于Int32.MaxValue。我怀疑Int64会好起来 - 所以请尝试将Convert.ToInt32更改为Convert.ToInt64

答案 1 :(得分:2)

List.sum使用抛出溢出的已检查运算符。你可以通过源追逐这个

List.sum calls Seq.sum
Seq.sum calls Checked.(+)

Checked.(+)在溢出时抛出错误。附注:这就是List.Fold (+)List.sum

更快的原因

要解决此问题,您需要将代码更改为使用64位整数(这应该足够大),我还要整理double和int之间的转换

let getPrimesUpTo (x : int64) =
    let upperBound = x |> float |>sqrt |> int64

    let allNumbers = ref [1L..x]    
    for div in 2L..upperBound do allNumbers := List.filter (fun num -> (num % div <> 0L || div >= num)) !allNumbers    
    allNumbers

let sop = 
    let nums = !(getPrimesUpTo 2000000L)
    List.sum nums

这种计算素数的方法非常低效。我已经编写了一些非常好的代码来计算F#中的大量素数 - 请参阅此处https://stackoverflow.com/a/8371684/124259