在项目euler#5中输入overflow

时间:2011-06-24 12:28:53

标签: f#

我正在尝试解决项目euler#5:

  

2520是可以除以1到10之间的每个数字的最小数字,没有任何余数。

     

从1到20的所有数字均可被整除的最小正数是多少?

这是我的代码:

open System

let rec gcd a b =
    match b with
        | x when x = 0 -> a
        | _ -> gcd b (a % b)

let lcm a b = (a * b) / (gcd a b)        
let result = Seq.fold lcm 1 [1..20]

[<EntryPoint>]
let main(args : string[]) =
    printfn "result = %d" result 
    0

它可以正常使用数字[1..19],但是数字[1..20]会得到错误的结果。 我试图找出错误的原因并找到:

$ Seq.fold lcm 1 [1..19]
232792560 // right
$ lcm 232792560 20
18044195 // wrong

看起来类型溢出。我该如何修复错误?

4 个答案:

答案 0 :(得分:7)

使用BigInt,一个不会溢出的整数类型。如果您在0中将0I替换为IBigInt后缀用于gcd文字),则gcd和{{1}我们将使用lcm代替BigInt s。

答案 1 :(得分:1)

另一个解决方案是稍微重新定义lcm函数

let lcm a b = let m = b / (gcd a b) in a * m;; 

由于您乘以稍微小一些的数字,它不会溢出。欧拉问题也与数学有关:p

答案 2 :(得分:1)

在其他语言中,可以使用4字节整数直到溢出,然后运行时升级整数,并按计划进行。

我想知道我们是否可以在F#中做同样的事情来优化性能。

答案 3 :(得分:0)

您可以使用LanguagePrimitives.GenericZero而不是文字0.这样,gcd函数和lcm函数都是通用的,可以使用任何数字类型。这是使用int64的解决方案:

module Problem5 =
    let rec greatestCommonDivisor a b  = // Euclidean algorithm
        if b = LanguagePrimitives.GenericZero then  a 
        else greatestCommonDivisor b (a % b)
    let leastCommonMultiple a b  = (a * b) / (greatestCommonDivisor a b)
    // Take the least common multiple of all numbers from 1 to 20.
    let solution = [1L..20L] |> List.fold leastCommonMultiple 1L