【问题标题】:Long multiplication in HaskellHaskell中的长乘法
【发布时间】:2017-11-15 18:56:40
【问题描述】:

您将如何在 Haskell 中的列表上实现长乘法。这个想法是,如果你有两个数字,比如说 112 和 13。这些数字可以表示为列表 [1,1,2] 和 [1,3],您希望将它们相乘以获得列表 [1, 4,5,6]。我想递归地执行此操作,因为我希望它适用于任何大小的列表。我的“functionWhichSumsLists”是我稍后将定义的函数,它将逐个元素添加两个列表。

longMulti l1 [] = p1
longMulti [] l2 = q1
longMulti (li:l1) (lii:l2) = functionWhichSumsLists [li*lii] (0:(longMulti l1 l2))

【问题讨论】:

  • 如果你想通过在Integer 之间来回转换来作弊:longMulti x y = longMulti x y = map (read . (:[])) . show $ read (concatMap show x) * read (concatMap show y)(它需要一个类型签名才能正常工作,因为read)。否则你将不得不考虑乘法是如何工作的,这就是我认为你真正追求的。第 1 步:在编码之前,详细解释如何将两个数字相乘。

标签: list haskell recursion multiplication


【解决方案1】:

您可以使用模运算,而不是使用show 来回转换String

toDigits :: Integral a => a -> [a]
toDigits = go [] where
  go acc 0 = acc
  go acc x = let (xs, x') = x `divMod` 10
             in go (x':acc) xs

那么fromDigits可以用foldl来实现。

import Data.List (foldl')

fromDigits :: Integral a => [a] -> a
fromDigits = foldl' (\acc x -> acc * 10 + x) 0

或者确实是zipWith (*)

-- note: this is significantly slower than above because of the necessary
--       calls to reverse.
fromDigits = sum . reverse . (zipWith (*) [10^i | i <- [0..]]) . reverse

剩下的就是乘法本身。不过要小心,因为幼稚的方法在这里行不通。

terms = [112, 13]
[xs, ys] = map toDigits terms
wrongAnswer = fromDigits $ zipWith (*) xs ys
-- 13

zipWith (*) [1, 1, 2] [1, 3],如上所述,变成[1*1, 1*3],当你坐下来想象它时,这显然是错误的。那么,我们必须交叉乘和求和,对吧?

alsoWrong = fromDigits $ answerDigits where
  answerDigits = zipWith (+) [map (*y) xs | y <- ys]
-- 448

这扩展为

zipWith (+) [map (*1) [1, 1, 2], map (*3) [1, 1, 2]]
= zipWith (+) [[1, 1, 2], [3, 3, 6]]
= [(1+3), (1+3), (2+6)]
= [4, 4, 8] -- fromDigits yields 448

这相当于手工操作:

    112
   x 13
   ----
    336
    112  <--- note this should be slid to the left
   ----
    448

因此,我们可以将类似的技术应用于将 fromDigits 折叠到每个术语。

sum $ map fromDigits $ zipWith (\p xs -> map (*p) xs) tens eachProduct where
  tens        = [10^i | i <- [len-1, len-2..0]]
  eachProduct = [map (*y) xs | y <- ys]
  len         = length eachProduct

结束:

longMultiplication :: Integral a => a -> a -> a
longMultiplication x y = sum . map fromDigits . zipWith mapper tens $ eachProduct where
    xs          = toDigits x
    ys          = toDigits y
    mapper      = (\p xs -> map (*p) xs)
    tens        = [10^i | i <- [len-1, len-2..0]]
    len         = length eachProduct
    eachProduct = [map (*y') xs | y' <- ys]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-25
    • 1970-01-01
    • 2016-04-16
    相关资源
    最近更新 更多