【问题标题】:Difference between `mod` and `rem` in HaskellHaskell中`mod`和`rem`之间的区别
【发布时间】:2011-08-18 23:13:42
【问题描述】:

Haskell 中 modrem 之间到底有什么区别?

两者似乎给出相同的结果

*Main> mod 2 3
2
*Main> rem 2 3
2
*Main> mod 10 5
0
*Main> rem 10 5
0
*Main> mod 1 0
*** Exception: divide by zero
*Main> rem 1 0
*** Exception: divide by zero
*Main> mod 1 (-1)
0
*Main> rem 1 (-1)
0

【问题讨论】:

  • 不知道 Haskell,但很可能这些是相同的操作。 modulus == remainder.
  • 公平地说,这不是同一个问题。另一个问题假设理解这个问题的答案。
  • @Dan 读到那个问题,因为我有另一个问题 (stackoverflow.com/questions/5892188/…),我意识到了同样的情况:/
  • 这和divquot之间的区别是一样的

标签: haskell


【解决方案1】:

当第二个参数为负时,它们不一样:

2 `mod` (-3)  ==  -1
2 `rem` (-3)  ==  2

【讨论】:

  • 我对 Clojure 中的 remmod 有同样的问题,这就是答案。
  • 当第一个参数为负时,它们也不相同。有关这些棘手操作的更多信息,请参阅 stackoverflow.com/a/8111203/1535283stackoverflow.com/a/339823/1535283
  • stackoverflow.com/a/6964760/205521 看来rem 是最快的。
  • 虽然这个答案是正确的,但对于“有什么区别”的问题声称不超过“不一样”的答案是一个非常糟糕的答案。如果您可以扩展它们的“不同之处”以及可能的一些用例,我会欢迎它。
【解决方案2】:

是的,这些功能的作用不同。如official documentation中所定义:

quot 是向零截断的整数除法

rem是整数余数,满足:

(x `quot` y)*y + (x `rem` y) == x

div 是向负无穷方向截断的整数除法

mod是整数模,满足:

(x `div` y)*y + (x `mod` y) == x

当您使用负数作为第二个参数并且结果不为零时,您可以真正注意到差异:

5 `mod` 3 == 2
5 `rem` 3 == 2

5 `mod` (-3) == -1
5 `rem` (-3) == 2

(-5) `mod` 3 == 1
(-5) `rem` 3 == -2

(-5) `mod` (-3) == -2
(-5) `rem` (-3) == -2

 

【讨论】:

  • 您的最后四个示例可能不是您的意思,因为modrem(-) 关联更紧密。我已编辑您的评论,因为我似乎无法在此评论中添加多行内容。
  • @ErikHesselink:您在编辑时引入了错误。 (-5) `mod` 3 == 1
  • @ChengSun 谢谢,我已经修好了。审核后应该会上线。
【解决方案3】:

实际上:

如果您知道两个操作数都是正数,则通常应该使用quotremquotRem 以提高效率。

如果您不知道两个操作数都是正数,则必须考虑您希望结果的样子。你可能不想要quotRem,但你也可能不想要divMod(x `div` y)*y + (x `mod` y) == x 定律是一个非常好的定律,但向负无穷大舍入除法(Knuth 式除法)通常不如确保 0 <= x `mod` y < y(欧几里得除法)有用且效率低。

【讨论】:

    【解决方案4】:

    如果您只想测试可分性,则应始终使用rem

    基本上x `mod` y == 0 等价于x `rem` y == 0,但remmod 快。

    【讨论】:

    【解决方案5】:
    quotRem' a b = (q, r) where
        q = truncate $ (fromIntegral a / fromIntegral b :: Rational)
        r = a - b * q
    divMod'  a b = (q, r) where
        q = floor    $ (fromIntegral a / fromIntegral b :: Rational)
        r = a - b * q
    

    例如:

    (-3) / 2 = -1.5
    (-3) `quot` 2 = truncate (-1.5) = -1
    (-3) `div`  2 = floor    (-1.5) = -2
    (-3) `rem` 2 = -3 - 2 * (-1) = -1
    (-3) `mod` 2 = -3 - 2 * (-2) = 1
    
    3 / (-2) = -1.5
    3 `quot` (-2) = truncate (-1.5) = -1
    3 `div`  (-2) = floor    (-1.5) = -2
    3 `rem` (-2) = 3 - (-2) * (-1) = 1
    3 `mod` (-2) = 3 - (-2) * (-2) = -1
    

    【讨论】:

    • 虽然此代码可能会解决问题,including an explanation 关于如何以及为什么解决问题将真正有助于提高您的帖子质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提问的人。请edit您的回答添加解释并说明适用的限制和假设。
    猜你喜欢
    • 2014-11-09
    • 1970-01-01
    • 2017-04-19
    • 2014-12-19
    • 2011-08-18
    • 1970-01-01
    • 2019-04-03
    • 1970-01-01
    • 2016-09-28
    相关资源
    最近更新 更多