如何处理F#中的算术运算OverflowException?

Nic*_*ick 2 python f#

我在F#中做Project Euler问题1:

3和5的倍数

如果我们列出10以下的所有自然数是3或5的倍数,我们得到3,5,6和9.这些倍数的总和是23.

求出1000以下3或5的所有倍数的总和.

这是我的尝试:

[1..999]
    |> List.filter (fun x -> x%3 * x%5 = 0)
    |> List.sum

val it : int = 233168
Run Code Online (Sandbox Code Playgroud)

我的朋友在Excel中通过添加3的倍数和5的倍数提取15的倍数来计算它,并且他用更大的上限来挑战我:找到1234567以下的所有3或5的倍数的总和.

我试过这个:

[1..1234567]
     |> List.filter (fun x -> x%3 * x%5 = 0)
     |> List.sum
Run Code Online (Sandbox Code Playgroud)

System.OverflowException:算术运算导致溢出.

第二次尝试:

let mutable result = 0
for x < 1000 do
    if  x%3 * x%5 = 0 then result = result + x
Run Code Online (Sandbox Code Playgroud)

错误FS0010:模式中出现意外的整数文字.预期的中缀运算符,引号或其他标记.

令我惊讶的是,Python可以很好地处理这个并且效率很高:

sum(x for x in range(1234567) if x%3 * x%5 == 0)
# 355636612814L

%time sum(x for x in range(1234567) if x%3 * x%5 == 0)
Wall time: 401 ms
Out: 355636612814L
Run Code Online (Sandbox Code Playgroud)

题:

  1. 为什么F#程序导致"算术运算导致溢出"?
  2. 是否可以在F#中编写上述python等效解决方案?
  3. 什么是解决这个问题的惯用F#方式?

seg*_*ved 6

你应该使用bigint作为大数字,就像这样

[1I..1234567I] 
    |> List.filter (fun x -> x % 3I * x % 5I = 0I) 
    |> List.sum
Run Code Online (Sandbox Code Playgroud)

或(不太可读)

[bigint  1..bigint 1234567] 
    |> List.filter (fun x -> x % bigint 3 * x % bigint 5 = bigint 0) 
    |> List.sum
Run Code Online (Sandbox Code Playgroud)

对于小于9,223,372,036,854,775,807的数字,您可以使用int64类型(带L后缀),使用int64可以提高整体性能

[1L..1234567L] 
    |> List.filter (fun x -> x % 3L * x % 5L = 0L) 
    |> List.sum
Run Code Online (Sandbox Code Playgroud)

  • 这个版本应该吸引python代码,万一你觉得变得势在必行:`如果x%3*x%5 = 0那么,让x = 1到1234567的变量sum = 0L,那么sum < - sum + int64 x` (3认同)