あなたがするときにJavaで
a % b
aが負の場合、本来のようにbにラップする代わりに、負の結果を返します。これを修正する最良の方法は何ですか?私が考えることができる唯一の方法は
a < 0 ? b + a : a % b
あなたがするときにJavaで
a % b
aが負の場合、本来のようにbにラップする代わりに、負の結果を返します。これを修正する最良の方法は何ですか?私が考えることができる唯一の方法は
a < 0 ? b + a : a % b
回答:
本来あるべき動作をします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
値には影響しません)。
(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
値には影響しません)。
a < 0
、多分あなたは見ることができるかもしれません)
(a % b + b) % b
非常に大きな値に対してはa
、が機能しなくなることに言及する価値がありb
ます。たとえば、a = Integer.MAX_VALUE - 1
and b = Integer.MAX_VALUE
を使用すると-3
、結果として負の数が得られますが、これは避けたいものです。
while
と、必要な場合を除いて、本当に必要な場合は遅くなりますif
。
Java 8以降では、Math.floorMod(int x、int y)とMath.floorMod(long x、long y)を使用できます。これらのメソッドはどちらも、Peterの回答と同じ結果を返します。
Math.floorMod( 2, 3) = 2
Math.floorMod(-2, 3) = 1
Math.floorMod( 2, -3) = -1
Math.floorMod(-2, -3) = -2
float
やdouble
引数では機能しません。Mod二項演算子(%
)もfloat
and double
オペランドで機能します。
Java 8をまだ使用していない(または使用できない)人々のために、Guavaは、Guava 11.0以降で利用可能なIntMath.mod()を使用して助けを求めました。
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分だとは言いませんが、両方の回答が基本方程式を満たしているとしても、15分と言います。
-1
代わりに選択するn-1
)。それでそれを持っています。
Java 8には Math.floorMod
がありますが、非常に低速です(その実装には複数の除算、乗算、および条件があります)。ただし、JVMには固有の最適化されたスタブがある可能性がありますが、これにより大幅にスピードアップします。
これを使わずにこれを行う最速の方法floorMod
は、ここでの他のいくつかの答えのようですが、条件付きブランチがなく、1つだけ遅い%
オペレーションがです。
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
入力がintの全範囲でランダムである場合、2つの解の両方の分布は同じになります。入力クラスターがゼロに近い場合、n - 1
後者のソリューションでは結果が少なすぎます。
ここに代替があります:
a < 0 ? b-1 - (-a-1) % b : a % b
これは、他の数式[(a%b + b)%b]よりも速い場合とそうでない場合があります。他の数式とは異なり、分岐が含まれていますが、使用するモジュロ演算は1つ少なくなっています。コンピュータが<0を正しく予測できる場合は、おそらく勝利です。
(編集:数式を修正しました。)