使Java模数的行为与负数一样的最佳方法是什么?

时间:2010-12-10 18:43:56

标签: java modulo negative-number

在java中执行

a % b

如果a为负数,则会返回否定结果,而不是像它应该的那样回绕到b。解决这个问题的最佳方法是什么?我能想到的唯一方法是

a < 0 ? b + a : a % b

6 个答案:

答案 0 :(得分:122)

它的行为应该是a%b = a - a / b * b;即它是剩下的。

你可以做(​​a%b + b)%b


此表达式的作用是(a % b)的结果必然低于b,无论a是正还是负。添加b会处理a的负值,因为(a % b)-b0之间的负值,(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

如果您只需要0n-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]更快,想到它。它包含一个对现代处理器通常不好的分支,但是使用一个较少的模运算。

实际上它肯定会慢一些。

(编辑:修正公式。)