我无法理解这两个 (
mod
& rem
) 函数之间的区别。
rem
示例描述了差异:
;; rem and mod are commonly used to get the remainder.
;; mod means Gaussian mod, so the result is always
;; non-negative. Don't confuse it with ANSI C's %
;; operator, which despite being pronounced
;; 'mod' actually implements rem, i.e. -10 % 3 = -1.
user=> (mod -10 3)
2
user=> (rem -10 3)
-1
mod
返回第一个数字的差值,以及小于第一个数字的第二个数字的最大整数(可能是负数)倍数:rem
只是剩下的部分。
例如
(rem -4 3) => -1
这里毫不奇怪:-4除以3是-1,-1“剩下”。(mod -4 3) => 2
:
因此,即使它们通常表现相似,mod 不返回余数,它做了一些更具体的事情。
差异以负数显示。
(rem -3 2)
为 -1,而 (mod -3 2)
为 1。
更一般地,
rem
函数被定义为补充quot
,即向零舍入的整数除法。所以这个关系总是成立:
(let [q (quot a b)
r (rem a b)]
(assert (= a (+ r (* q b)))))
例如,
(quot -3 2)
是-1,(rem -3 2)
是-1,而(+ -1 (* -1 2))
确实是-3。
mod
函数被定义为使得 (mod a b)
对于正 b 的结果始终在 [0,b-1] 范围内,即使 a 为负。这通常是您对“模算术”的期望;无论您朝哪个方向走,都会永远重复相同的数字。
它与整数除法运算结合使用特别有用,整数除法运算向下舍入而不是向零舍入(也就是说,如果答案是否定的,四舍五入的答案更负),不幸的是,Clojure 没有预定义函数。不过,您可以定义自己的:
(defn div [a b] (int (. Math floor (/ a b))))
那么
(div -3 2)
就是-2,因为-2 * 2 = -4是小于等于-3的2的最大偶数倍。 (同样,-2 是小于或等于-1.5 的最大整数。)
事实上,这就是许多其他语言中整数除法的定义方式,例如 Common Lisp(双参数
floor
函数)、Python(//
运算符)、Ruby(Integer#div
方法)等。
定义了这样的函数后,上述对
quot
/rem
的断言也适用于 div
/mod
:
(let [q (div a b)
r (mod a b)]
(assert (= a (+ r (* q b)))))
例如,
(div -3 2)
为 -2,(mod -3 2)
为 1,(+ 1 (* -2 2))
再次等于 -3。
数学表示:
rem (a, b) = a - (quot (a, b) * b)
mod (a, b) = a - (floor (a / b) * b)
用实际例子来说明差异:
;; Using rem
(rem 7 3) ; => 1
(rem -7 3) ; => -1
(rem 7 -3) ; => 1
(rem -7 -3) ; => -1
;; Using mod
(mod 7 3) ; => 1
(mod -7 3) ; => 2
(mod 7 -3) ; => -2
(mod -7 -3) ; => -2