【问题标题】:f# sum a List of Int32 throws Arithmetic operation resulted in an overflowf# sum a List of Int32 throws 算术运算导致溢出
【发布时间】:2012-05-24 18:47:10
【问题描述】:

我正在尝试获取从 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,我会得到素数列表

【问题讨论】:

    标签: .net f#


    【解决方案1】:

    大概List.sum 将尝试将这些值求和为Int32 值...并且大概2,000,000 的质数之和大于Int32.MaxValue。我怀疑Int64 会没问题 - 所以尝试将Convert.ToInt32 更改为Convert.ToInt64

    【讨论】:

    • 另外,我得到一个 Int32 数字列表,唯一的问题是 List.Sum
    • @ChuckNorris:在不熟悉 F# 的情况下,您能否将转换指定为 List.sum 调用的一部分?例如List.sum nums Convert.ToInt64
    • @JonSkeet - 你可以改成List.sum (List.map int64 (!(getPrimesUpTo 2000000L))
    【解决方案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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-05-15
      • 2011-05-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多