46

从haskell报告中:

如果 y 不为零,则 quot、rem、div 和 mod 类方法满足这些定律:

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

quot是整数除法向零截断,而结果div 是向负无穷大截断。

例如:

Prelude> (-12) `quot` 5
-2
Prelude> (-12) `div` 5
-3

有哪些例子可以说明截断结果的方式之间的差异很重要?

4

3 回答 3

40

许多语言都有一个“mod”或“%”运算符,它给出除法后的余数,并截断为 0;例如 C、C++ 和 Java,可能还有 C#,会说:

(-11)/5 = -2
(-11)%5 = -1
5*((-11)/5) + (-11)%5 = 5*(-2) + (-1) = -11.

Haskell 的quotrem旨在模仿这种行为。我可以想象在某些人为的情况下可能需要与某些 C 程序的输出兼容。

Haskell 的divandmod以及随后的 Python 的 / 和 % 遵循数学家(至少是数论家)的惯例,总是将除法截断而不是朝向 0 - 朝向负无穷大),因此余数总是非负的。因此在 Python 中,

(-11)/5 = -3
(-11)%5 = 4
5*((-11)/5) + (-11)%5 = 5*(-3) + 4 = -11.

Haskelldivmod遵循这种行为。

于 2008-12-04T07:52:36.930 回答
27

这不完全是您问题的答案,但在 x86 上的 GHC 中,Int 上的 quotRem 将编译为单个机器指令,而 divMod 做了更多的工作。因此,如果您处于对速度至关重要的部分并且只处理正数,那么 quotRem 是要走的路。

于 2008-12-04T22:53:20.357 回答
7

一个重要的简单示例是测试整数是偶数还是奇数。

let buggyOdd x = x `rem` 2 == 1
buggyOdd 1 // True
buggyOdd (-1) // False (wrong!)

let odd x = x `mod` 2 == 1
odd 1 // True
odd (-1) // True

请注意,当然,您可以通过以这种方式定义奇数来避免考虑这些问题:

let odd x = x `rem` 2 /= 0
odd 1 // True
odd (-1) // True

一般来说,请记住,对于y > 0x mod y总是返回一些东西>= 0,而x rem y返回 0 或与 x 符号相同的东西。

于 2008-12-04T07:00:36.910 回答