Haskell中`mod`和`rem`之间的区别

Posted

技术标签:

【中文标题】Haskell中`mod`和`rem`之间的区别【英文标题】:Difference between `mod` and `rem` in Haskell 【发布时间】: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 读到那个问题,因为我有另一个问题 (***.com/questions/5892188/…),我意识到了同样的情况:/ 这和divquot之间的区别是一样的 【参考方案1】:

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

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

【讨论】:

我对 Clojure 中的 remmod 有同样的问题,这就是答案。 当第一个参数为负时,它们也不相同。有关这些棘手操作的更多信息,请参阅 ***.com/a/8111203/1535283 和 ***.com/a/339823/1535283。 从***.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 快。

【讨论】:

为什么remmod 更快? 至少在IntInteger的情况下,mod是按照rem来实现的,但是需要一些额外的检查:hackage.haskell.org/package/ghc-prim-0.7.0/docs/src/…,hackage.haskell.org/package/integer-gmp-1.0.3.0/docs/src/…【参考方案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您的回答添加解释并说明适用的限制和假设。

以上是关于Haskell中`mod`和`rem`之间的区别的主要内容,如果未能解决你的问题,请参考以下文章

matlab里rem和mod函数区别?

matlab里rem和mod函数区别?

Matlab中取模(mod)与取余(rem)的区别

Haskell中的模块化算法

matlab中mod是啥意思

matlab中rem函数的作用?