Sum of Squares using Haskell

前端 未结 3 1828
梦毁少年i
梦毁少年i 2020-12-06 23:31

I\'m trying to carry out the following computation: sum of the squares of integers in the range x:y where (x <= y).

I\'m not sure how to put a constraint to ensur

相关标签:
3条回答
  • 2020-12-06 23:58

    In GHCI do these steps to see what's going on:

    Prelude> let sq x = x^2
    Prelude> let list = [1..5]
    Prelude> list
    [1,2,3,4,5]
    Prelude> let listOfSq = map sq list
    Prelude> listOfSq
    [1,4,9,16,25]
    
    Prelude> sum listOfSq
    55
    

    The shorthand would be exactly what Jubobs suggested:

    sum $ map (^2) [1..5]
    

    EDIT: To error out when Y is greater than X you can do something like this

    sumOfSquares :: Integer -> Integer -> Integer
    sumOfSquares x y  | y <= x = error "Y must be greater than X"
                      | otherwise = sum $ map (^2) [x..y]
    
    0 讨论(0)
  • 2020-12-07 00:03

    Slow approach

    The obvious and slow approach is to actually sum those squares:

    sumOfSquaresSlow :: Integral a => a -> a -> a
    sumOfSquaresSlow lo hi
        | lo > hi   = error "sumOfSquaresSlow: lo > hi"
        | otherwise = sum $ map (^2) [lo..hi]
    

    The time complexity of this approach is linear in max(y-x,0); it will take a while if your range of integers is large; see the benchmark at the bottom of my answer.

    Faster approach

    However, because there is a formula for the sum of the squares of the first n (positive) integers, you don't actually have to sum those squares one by one.

    To issue an error message to the user in case x is greater that y (as specified in your comment), you can simply use the error function, here.

    (Edit: thanks to Chris Drost for pointing out that I was overcomplicating things)

    sumOfSquaresFast :: Integral a => a -> a -> a
    sumOfSquaresFast lo hi
        | lo > hi   = error "sumOfSquaresFast: lo > hi"
        | otherwise = ssq hi - ssq (lo - 1)
      where
        ssq x = div (((2 * x + 3) * x + 1) * x) 6
    

    Using this formula instead reduces the complexity to something close to constant time.

    Benchmark in GHCi

    λ> :set +s
    
    λ> sumOfSquaresSlow (10^3)  (10^7)
    333333383333002166500
    (17.19 secs, 11563005552 bytes)
    
    λ> sumOfSquaresFast (10^3) (10^7)
    333333383333002166500
    (0.01 secs, 3106112 bytes)
    
    0 讨论(0)
  • 2020-12-07 00:16

    Using list comprehension:

    squareSum from to
      | from > to = error "wrong input"
      | otherwise = sum [i^2 | i <- [from..to]]
    

    UPDATE: updated after OP has updated the question

    0 讨论(0)
提交回复
热议问题