【发布时间】:2017-05-02 00:11:37
【问题描述】:
负数的模如何在 swift 中起作用? 当我执行 (-1 % 3) 时,它给出 -1 但余数为 2。其中有什么问题?
【问题讨论】:
负数的模如何在 swift 中起作用? 当我执行 (-1 % 3) 时,它给出 -1 但余数为 2。其中有什么问题?
【问题讨论】:
Swift 余数运算符 % 计算余数
整数除法:
a % b = a - (a/b) * b
其中/ 是截断整数除法。你的情况
(-1) % 3 = (-1) - ((-1)/3) * 3 = (-1) - 0 * 3 = -1
所以余数总是与红利有相同的符号(除非 余数为零)。
这与所需的定义相同,例如在 C99 标准中, 例如见 Does either ANSI C or ISO C specify what -5 % 10 should be?。也可以看看 Wikipedia: Modulo operation 概览 这在不同的编程语言中是如何处理的。
在 Swift 中可以像这样定义“真正的”模数函数:
func mod(_ a: Int, _ n: Int) -> Int {
precondition(n > 0, "modulus must be positive")
let r = a % n
return r >= 0 ? r : r + n
}
print(mod(-1, 3)) // 2
【讨论】:
来自Language Guide - Basic Operators:
余数运算符
余数运算符 (
a % b) 计算出b的倍数 将适合a并返回剩余的值(称为 剩下的)。余数运算符 (
%) 在 其他语言。然而,它在 Swift 中对负数的行为 意味着严格来说,它是余数而不是模数 操作。...
计算a的余数时应用相同的方法 a的负值:
-9 % 4 // equals -1将
-9和4插入方程得到:-9 = (4 x -2) + -1给出
-1的余数。
在您的情况下,没有3 适合1,余数为1(与-1 相同 -> 余数为-1)。
【讨论】:
-9的4的最大倍数”不是很清楚...
如果您真正追求的是捕获 0 和 b 之间的数字,请尝试使用以下方法:
infix operator %%
extension Int {
static func %% (_ left: Int, _ right: Int) -> Int {
if left >= 0 { return left % right }
if left >= -right { return (left+right) }
return ((left % right)+right)%right
}
}
print(-1 %% 3) //prints 2
这将适用于 a 的所有值,与之前的答案不同,而仅在 a > -b 时才有效。
我更喜欢 %% 运算符,而不是仅仅重载 %,因为很明显你不是在做一个真正的 mod 函数。
if 语句的原因,而不是仅仅使用最后的返回行,是为了速度,因为 mod 函数需要除法,而除法比条件更昂贵。
【讨论】:
一个受 cdeerinck 启发的答案,为了简单而牺牲速度,是这样的:
infix operator %%
extension Int {
static func %% (_ left: Int, _ right: Int) -> Int {
let mod = left % right
return mod >= 0 ? mod : mod + right
}
}
我在操场上用这个小循环对其进行了测试:
for test in [6, 5, 4, 0, -1, -2, -100, -101] {
print(test, "%% 5", test %% 5)
}
【讨论】: