在java中执行
a % b
如果a为负数,则会返回否定结果,而不是像它应该的那样回绕到b。解决这个问题的最佳方法是什么?我能想到的唯一方法是
a < 0 ? b + a : a % b
答案 0 :(得分:122)
它的行为应该是a%b = a - a / b * b;即它是剩下的。
你可以做(a%b + b)%b
此表达式的作用是(a % b)
的结果必然低于b
,无论a
是正还是负。添加b
会处理a
的负值,因为(a % b)
是-b
和0
之间的负值,(a % b + b)
必然更低比b
和积极的。如果a
为肯定a
,(a % b + b)
会变得大于b
,那么最后一个模数就是(a % b + b) % b
为正。因此,b
再次将其变为小于a
(并且不会影响负{{1}}值)。
答案 1 :(得分:78)
从Java 8开始,您可以使用Math.floorMod(int x, int y)和Math.floorMod(long x, long y)。这两种方法都返回与彼得答案相同的结果。
Math.floorMod( 2, 3) = 2
Math.floorMod(-2, 3) = 1
Math.floorMod( 2, -3) = -1
Math.floorMod(-2, -3) = -2
答案 2 :(得分:10)
对于那些还没有使用(或不能使用)Java 8的人来说,Guava用IntMath.mod()来救援,自Guava 11.0开始提供。
IntMath.mod( 2, 3) = 2
IntMath.mod(-2, 3) = 1
一个警告:与Java 8的Math.floorMod()不同,除数(第二个参数)不能为负数。
答案 3 :(得分:7)
在数论中,结果总是正面的。我猜想在计算机语言中并非总是如此,因为并非所有程序员都是数学家。我的两分钱,我认为这是该语言的设计缺陷,但你现在无法改变它。
= MOD(-4,180)= 176 = MOD(176,180)= 176
因为180 *( - 1)+ 176 = -4与180 * 0 + 176 = 176
相同在此处使用时钟示例,http://mathworld.wolfram.com/Congruence.html 你不会说duration_of_time mod cycle_length是-45分钟,你会说15分钟,即使两个答案都满足基本方程式。
答案 4 :(得分:1)
Java 8具有Math.floorMod
,但是它非常慢(其实现具有多个除法,乘法和条件运算)。但是,JVM可能具有针对其进行内部优化的存根,这将大大提高其速度。
在没有floorMod
的情况下执行此操作的最快方法与此处的其他答案类似,但是没有条件分支并且只有一个缓慢的%
操作。
假设n为正,并且x可以是任何东西:
int remainder = (x % n); // may be negative if x is negative
//if remainder is negative, adds n, otherwise adds 0
return ((remainder >> 31) & n) + remainder;
n = 3
时的结果:
x | result
----------
-4| 2
-3| 0
-2| 1
-1| 2
0| 0
1| 1
2| 2
3| 0
4| 1
如果您只需要0
和n-1
之间的均匀分布而不是确切的mod运算符,并且您的x
不在0
附近聚集,请执行以下操作由于存在更多的指令级并行性,因此%
运算速度会更快,因为它们不依赖于其结果,因此return ((x >> 31) & (n - 1)) + (x % n)
计算将与其他部分并行进行。
n = 3
使用x | result
----------
-5| 0
-4| 1
-3| 2
-2| 0
-1| 1
0| 0
1| 1
2| 2
3| 0
4| 1
5| 2
的上述结果:
n - 1
如果输入在int的整个范围内都是随机的,则两个解的分布将相同。如果输入簇接近零,则后一种解决方案的<!--HTML-->
<section id="newsletter">
<div class="container">
<h1>Subscribe to our Newsletter</h1>
<form>
<input type="email" placeholder="Enter Email...">
<button type="submit" class="button1">Subscribe</button>
</form>
</div>
</section>
处的结果将太少。
答案 5 :(得分:0)
这是另一种选择:
a < 0 ? b-1 - (-a-1) % b : a % b
这可能会或可能不会比其他公式[(a%b + b)%b]更快,想到它。它包含一个对现代处理器通常不好的分支,但是使用一个较少的模运算。
实际上它肯定会慢一些。
(编辑:修正公式。)