In Javaするとき
a % b
Aが負の場合、bにラップするのではなく、負の結果を返します。これを修正する最良の方法は何ですか?私が考えることができる唯一の方法は
a < 0 ? b + a : a % b
A%b = a-a/b * bのように動作します。つまり、残りの部分です。
あなたはできる(a%b + b)%b
この式は、b
が正でも負でも、_(a % b)
_がa
よりも必ず低い結果として機能します。 _(a % b)
_は_-b
_と_0
_の間の負の値であるため、b
の追加はa
の負の値を処理します。_(a % b + b)
_は必然的にb
より低く、正。 a
が正の場合_(a % b + b)
_はa
より大きくなるため、b
が最初から正であった場合に最後のモジュロがあります。したがって、_(a % b + b) % b
_は再びb
より小さくなります(負のa
値には影響しません)。
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
使用していない(または使用できない)Java 8、まだGuavaは IntMath.mod() で救助に来ました。Guava11.0以降で使用可能です。
IntMath.mod( 2, 3) = 2
IntMath.mod(-2, 3) = 1
1つの注意:Java 8のMath.floorMod()とは異なり、除数(2番目のパラメーター)は負にできません。
数論では、結果は常に正です。すべてのプログラマーが数学者であるとは限らないので、これはコンピューター言語では必ずしも当てはまらないと思います。私の2セントは、それを言語の設計上の欠陥と考えていますが、今では変更できません。
= 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分であるとは言えません。両方の答えが基本方程式。
Java 8には_Math.floorMod
_がありますが、非常に低速です(その実装には複数の除算、乗算、および条件があります)。ただし、JVMに固有の最適化されたスタブがある可能性があります。これにより、JVMが大幅に高速化されます。
floorMod
なしでこれを行う最速の方法は、他のいくつかの回答と同様ですが、条件分岐がなく、遅い_%
_ opのみです。
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
_
正確なmod演算子ではなく、_0
_と_n-1
_の間の均一な分散のみが必要であり、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
_
入力がintの全範囲でランダムな場合、両方の2つのソリューションの分布は同じになります。入力がゼロに近い場合、後者のソリューションでは_n - 1
_で結果が少なすぎます。
以下が代替案です。
a < 0 ? b-1 - (-a-1) % b : a % b
これは、他の式[(a%b + b)%b]より速いかもしれないし、そうでないかもしれません。通常、最新のプロセッサでは問題のあるブランチが含まれていますが、モジュロ演算が1つ少なくなります。
実際、それは間違いなく遅いかもしれません。
(編集:数式を修正しました。)