它的行为应该是:a % b = a - a / b * b,也就是余数 你可以做(a % b + b) % b。 这个表达式的作用是,无论a是正的还是负的,(a % b)都必须小于b。加上b会处理a的负值,因为(a % b)是-b和0之间的负值。(a % b + b)必须小于b且为正。如果a开始为正,则存在最后一个模,因为如果a为正,则(a % b + b)将变得大于b。因此,(a % b + b) % b将其再次变为小于b(并且不影响负a值)。
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;
7条答案
按热度按时间yduiuuwa1#
它的行为应该是:
a % b = a - a / b * b
,也就是余数你可以做
(a % b + b) % b
。这个表达式的作用是,无论
a
是正的还是负的,(a % b)
都必须小于b
。加上b
会处理a
的负值,因为(a % b)
是-b
和0
之间的负值。(a % b + b)
必须小于b
且为正。如果a
开始为正,则存在最后一个模,因为如果a
为正,则(a % b + b)
将变得大于b
。因此,(a % b + b) % b
将其再次变为小于b
(并且不影响负a
值)。polkgigr2#
从Java 8开始,可以使用Math.floorMod(int x,int y)和Math.floorMod(long x,long y),这两种方法返回的结果与Peter的答案相同。
mqxuamgl3#
对于那些还没有使用(或不能使用)Java8的人,Guava用IntMath.mod()来拯救他们,从Guava 11.0开始就可以使用。
需要注意的是:与Java8的Math.floorMod()不同,除数(第二个参数)不能为负。
0ejtzxu14#
在数论中,结果总是正的。我猜计算机语言中并不总是这样,因为并不是所有的程序员都是数学家。恕我直言,我会认为这是语言的设计缺陷,但你现在不能改变它。
=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分钟,即使两个答案都满足基本方程。
5f0d552i5#
Java 8有
Math.floorMod
,但是它非常慢(它的实现有多个除法、乘法和一个条件)。不过,JVM可能有一个内在的优化存根,这将大大加快它的速度。在没有
floorMod
的情况下,完成此操作的最快方法与此处的其他答案类似,但没有条件分支,只有一个缓慢的%
操作。假设n为正,x可以是任意值:
n = 3
时的结果:如果您只需要
0
和n-1
之间的均匀分布,而不需要精确的mod运算符,并且您的x
不聚集在0
附近,那么下面的操作会更快,因为有更多的指令级并行性,并且缓慢的%
计算将与其他部分并行发生,因为它们不依赖于其结果。return ((x >> 31) & (n - 1)) + (x % n)
上述
n = 3
的结果:如果输入在整数的整个范围内是随机的,那么两个解的分布将是相同的,如果输入聚类接近零,那么在后一个解中
n - 1
处的结果将太少。agxfikkp6#
下面是一个替代方案:
这可能比另一个公式[(a % b + b)% b]快,也可能不快。与另一个公式不同,它包含一个分支,但使用的模运算少一个。如果计算机能正确预测〈0,可能会成功。
(Edit:修正了公式。)
z9ju0rcb7#
floorMod方法是最好的方法。
我很惊讶没有人张贴明显的。