Computing the mean of a list efficiently in Haskell

后端 未结 6 1920
傲寒
傲寒 2021-02-04 11:21

I\'ve designed a function to compute the mean of a list. Although it works fine, but I think it may not be the best solution due to it takes two functions rather than one. Is it

6条回答
  •  情书的邮戳
    2021-02-04 11:43

    About the best you can do is this version:

    import qualified Data.Vector.Unboxed as U
    
    data Pair = Pair {-# UNPACK #-}!Int {-# UNPACK #-}!Double
    
    mean :: U.Vector Double -> Double
    mean xs = s / fromIntegral n
      where
        Pair n s       = U.foldl' k (Pair 0 0) xs
        k (Pair n s) x = Pair (n+1) (s+x)
    
    main = print (mean $ U.enumFromN 1 (10^7))
    

    It fuses to an optimal loop in Core (the best Haskell you could write):

    main_$s$wfoldlM'_loop :: Int#
                                  -> Double#
                                  -> Double#
                                  -> Int#
                                  -> (# Int#, Double# #)    
    main_$s$wfoldlM'_loop =
      \ (sc_s1nH :: Int#)
        (sc1_s1nI :: Double#)
        (sc2_s1nJ :: Double#)
        (sc3_s1nK :: Int#) ->
        case ># sc_s1nH 0 of _ {
          False -> (# sc3_s1nK, sc2_s1nJ #);
          True ->
            main_$s$wfoldlM'_loop
              (-# sc_s1nH 1)
              (+## sc1_s1nI 1.0)
              (+## sc2_s1nJ sc1_s1nI)
              (+# sc3_s1nK 1)
        }
    

    And the following assembly:

    Main_mainzuzdszdwfoldlMzqzuloop_info:
    .Lc1pN:
            testq %r14,%r14
            jg .Lc1pQ
            movq %rsi,%rbx
            movsd %xmm6,%xmm5
            jmp *(%rbp)
    .Lc1pQ:
            leaq 1(%rsi),%rax
            movsd %xmm6,%xmm0
            addsd %xmm5,%xmm0
            movsd %xmm5,%xmm7
            addsd .Ln1pS(%rip),%xmm7
            decq %r14
            movsd %xmm7,%xmm5
            movsd %xmm0,%xmm6
            movq %rax,%rsi
            jmp Main_mainzuzdszdwfoldlMzqzuloop_info
    

    Based on Data.Vector. For example,

    $ ghc -Odph --make A.hs -fforce-recomp
    [1 of 1] Compiling Main             ( A.hs, A.o )
    Linking A ...
    $ time ./A
    5000000.5
    ./A  0.04s user 0.00s system 93% cpu 0.046 total
    

    See the efficient implementations in the statistics package.

提交回复
热议问题