Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/314.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何在F#中处理算术运算溢出异常?_Python_F# - Fatal编程技术网

Python 如何在F#中处理算术运算溢出异常?

Python 如何在F#中处理算术运算溢出异常?,python,f#,Python,F#,我正在做F#中的欧拉计划问题1: 3和5的倍数 如果我们列出10以下的所有自然数,它们是3或5的倍数,我们得到3、5、6和9。这些倍数之和是23 求1000以下所有3或5的倍数之和 以下是我的尝试: [1..999] |>List.filter(乐趣x->x%3*x%5=0) |>List.sum val it:int=233168 我的朋友在Excel中通过将3的倍数和5的倍数相加并提取15的倍数来计算,他用一个更大的上限来挑战我:找到1234567以下所有3或5的倍数之和 我试过这个: [

我正在做F#中的欧拉计划问题1:

3和5的倍数

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

求1000以下所有3或5的倍数之和

以下是我的尝试:

[1..999]
|>List.filter(乐趣x->x%3*x%5=0)
|>List.sum
val it:int=233168
我的朋友在Excel中通过将3的倍数和5的倍数相加并提取15的倍数来计算,他用一个更大的上限来挑战我:找到1234567以下所有3或5的倍数之和

我试过这个:

[1..1234567]
|>List.filter(乐趣x->x%3*x%5=0)
|>List.sum
System.OverflowException
:算术运算导致溢出

第二次尝试:

让可变结果=0
对于x<1000 do
如果x%3*x%5=0,则结果=结果+x
错误FS0010:模式中存在意外的整数文字。应为中缀运算符、引号符号或其他标记

令我惊讶的是,Python能够很好地处理这一问题,而且效率很高:

sum(如果x%3*x%5==0,则x代表范围(1234567)内的x)
#35563612814L
%时间和(如果x%3*x%5==0,则x代表范围(1234567)内的x)
墙壁时间:401毫秒
输出:35566612814L
问题:

  • 为什么F#程序会导致“算术运算导致溢出”
  • 是否可以用F#编写上述python等效解决方案
  • 解决这个问题的惯用方法是什么

  • 对于大的数字,应该使用bigint,如下所示

    [1I..1234567I] 
        |> List.filter (fun x -> x % 3I * x % 5I = 0I) 
        |> List.sum
    
    或(可读性较差)

    对于数字,您也可以使用int64类型(带L后缀),使用int64可以提高整体性能

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

    在我的机器上,直接翻译Python代码只需运行一半的时间,158毫秒(Python为317毫秒)

    seq { 
        for x in 0L..1234566L do 
            if x % 3L * x % 5L = 0L then
                yield x
    }
    |> Seq.sum
    
    这段可以说更惯用的代码仍然比Python(220毫秒)运行得更快

    即使是LINQ版本也更快(221ms)


    让我试着回答你的问题:

  • 为什么F#程序会导致“算术运算导致溢出”
  • 溢出错误是由于32位有符号整数(2^31-1=2147483647)的可表示范围受到限制而发生的。当排除上限为1234567时,答案如下:

    Sum of all natural numbers up to 1234567 divisible by 3 or by 5 is 355,636,612,814
    Result was computed in 12 ms
    
  • 是否可以用F#编写上述python等效解决方案
  • 下面是与Python实现类似的完整程序。它可以说是以命令式风格编写的,但它完成工作的速度很快

    open System.Diagnostics
    
    [<EntryPoint>]
    let main argv = 
       let limit_exclusive = 1234567
       let limit = limit_exclusive - 1
       let divisor1 = 3
       let divisor2 = 5
    
       let stopwatch = Stopwatch.StartNew()
       let mutable sum = 0UL
    
       for x = 1 to limit do 
          if (x % divisor1 = 0) || (x % divisor2 = 0) then 
             sum <- sum + uint64 x
    
       stopwatch.Stop()
    
       printfn "Sum of all natural numbers up to %d divisible by %d or by %d is %d" limit_exclusive divisor1 divisor2 sum
       printfn "Result was computed in %d ms" stopwatch.ElapsedMilliseconds
    
       0 // return an integer exit code
    
    Sum of all natural numbers up to 1234567 divisible by 3 or by 5 is 355,636,612,814
    Result was computed in 12 ms
    

    请注意,结果是一个大数字-Python具有任意精度整数(在2.x中,它们在某一点上变长,如您所见),但F#没有-例如,非常感谢
    int64(L)
    是一个很好的解决方案。我在我的电脑上运行了它,花费了
    598 ms
    。我想知道为什么它比python慢,因为python是解释的,F#是JIT编译的?通过创建
    [1L..1234567L]
    实际上创建了列表,然后过滤元素(在过程中复制列表),然后对结果求和。如果您使用
    seq{1L..1234567L}
    seq.filter
    seq.sum
    ,那么内存应该会更少,而且很可能运行得更快。@Danielbabian是的,
    seq
    列表
    快,在我的计算机上花了
    488 ms
    ,仍然比Python慢。虽然执行时间在这个问题上并不重要,但性能让我感到惊讶。(谢谢你)这个版本应该会让python代码冒烟,以防你觉得有必要:
    让x=1到1234567的可变sum=0L,如果x%3*x%5=0,那么求和很好,是和否。是的,肯定会有一些开销,但大约95%的时间与此无关。再加上功能性思维允许您进行高级优化,这是由于可变状态而不允许的。也就是说,当您确实需要性能时,有时可能会以命令式风格重写某些内部循环。(我们做大量的数字运算,除了一些矩阵mul循环外,我们仍然以函数式的方式做所有事情)是的,在我的计算机上是
    233ms
    ,大约是Python的一半时间。这是合理的;它解决了我对Interped语言和JIT编译语言性能的混乱理解。非常感谢。
    query {
        for x in 0L .. 1234566L do
        where (x % 3L * x % 5L = 0L)
        sumBy x
    }
    
    Sum of all natural numbers up to 1234567 divisible by 3 or by 5 is 355,636,612,814
    Result was computed in 12 ms
    
    open System.Diagnostics
    
    [<EntryPoint>]
    let main argv = 
       let limit_exclusive = 1234567
       let limit = limit_exclusive - 1
       let divisor1 = 3
       let divisor2 = 5
    
       let stopwatch = Stopwatch.StartNew()
       let mutable sum = 0UL
    
       for x = 1 to limit do 
          if (x % divisor1 = 0) || (x % divisor2 = 0) then 
             sum <- sum + uint64 x
    
       stopwatch.Stop()
    
       printfn "Sum of all natural numbers up to %d divisible by %d or by %d is %d" limit_exclusive divisor1 divisor2 sum
       printfn "Result was computed in %d ms" stopwatch.ElapsedMilliseconds
    
       0 // return an integer exit code
    
    Sum of all natural numbers up to 1234567 divisible by 3 or by 5 is 355,636,612,814
    Result was computed in 12 ms
    
       let seq1 = seq { 0 .. divisor1 .. limit }
       let seq2 = seq { 0 .. divisor2 .. limit }
    
       let both = Seq.append seq1 seq2
       let sum = both
                 |> Seq.distinct
                 |> Seq.map uint64
                 |> Seq.sum
    
    Sum of all natural numbers up to 1234567 divisible by 3 or by 5 is 355,636,612,814
    Result was computed in 535 ms