Kotlin负数取模返回负值

22

在 Kotlin 中,对于函数 a.mod(n),如果 a 为负数,则结果也为负数,这不符合模运算的本意。我该怎么做才能始终得到正数的余数?

例如:

(-2).mod(9)

返回值为-2,应该为7


1
实际上,在大多数编程语言中,负号是预期的,因为这就是模运算的工作方式。https://dev59.com/Bmgu5IYBdhLWcg3wCCxK - egor.zhdan
11
仅仅因为某个行为很普遍,并不意味着它是正确的。我从来没有希望过 C++ 的行为,而一直想要数学上的行为。考虑一个非常常见的情况,即使用 arrayOfStuff[curIndex - 1] 遍历数组。当当前索引为零时,你更愿意绕回到末尾,还是抛出异常? - treat your mods well
1
谁认为在Kotlin中获得模数的负结果是个好主意? - dstibbe
4个回答

18

最佳答案是 Math.floorMod(),正如Paul Lammertsma在评论中提到的那样,因为它在数学上是最正确的:它始终返回一个值,介于零(包括)和除数(不包括)之间,并且无论两个参数是否都是负数,都能实现这一点。

甚至在翻转所有输入和输出的符号时,它也保持不变:

Math.floorMod(11, 9) => 2
Math.floorMod(-11, -9) => -2

Math.floorMod(-11, 9) => 7
Math.floorMod(11, -9) => -7

Math.floorMod 自 JDK 1.8 起可用。


12

在 Kotlin 1.1 版本中,mod 已经被弃用,因为它是计算除法的余数,这可能会产生负数。这就是为什么他们改成了 rem,这个名称更符合其功能。如果你想在 Kotlin 中使用模运算函数,以及大多数其他语言,可以使用以下代码:

r = (a).rem(n)
if (r < 0) r += n

2
这个解决方案无法处理 (-11).rem(9) 的情况,因为它仍然会返回 2 而不是 7。最好使用 Math.floorMod() - Paul Lammertsma
如果您想要最佳效果,可以将答案作为另一种选项进行编辑。 - Damia Fuentes
这个答案现在有点过时了。从 Kotlin 1.5 开始,mod 的工作方式符合 OP 的预期。 - sbarzowski

11

而且大括号非常重要 :P - dstibbe

0

对于轮播数组访问,只要负数不低于数组大小,使用%或rem都可以解决问题。

所以,如果您在大小为16的数组中旋转:

(11 + 16) % 16 => 11

(-11 + 16) % 16 => 5

(-15 + 16) % 16 => 1

(-16 + 16) % 16 => 0

(0 + 16) % 16 => 0

无需调用额外的函数,因此我预计这将更快(未经测试)。

(16 + 16) % 16 => 0


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接