我正在尝试解决项目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
看起来类型溢出。我该如何修复错误?
答案 0 :(得分:7)
使用BigInt
,一个不会溢出的整数类型。如果您在0
中将0I
替换为I
(BigInt
后缀用于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