자바에서 할 때
a % b
a가 음수이면 b로 감싸는 대신 부정적인 결과를 반환합니다. 이 문제를 해결하는 가장 좋은 방법은 무엇입니까? 내가 생각할 수있는 유일한 방법은
a < 0 ? b + a : a % b
자바에서 할 때
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
IF (아무리 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
매우 큰 값에 대해 분류된다는 점을 언급 할 가치가 있습니다 . 예를 들어, and will give as result, which is the negative number, which is what you want to avoid. a
b
a = Integer.MAX_VALUE - 1
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
및 double
피연산자 와 함께 작동합니다 .
아직 Java 8을 사용하지 않거나 사용할 수없는 사람들을 위해 Guava는 Guava 11.0부터 사용할 수 있는 IntMath.mod () 를 사용 하여 구출했습니다 .
IntMath.mod( 2, 3) = 2
IntMath.mod(-2, 3) = 1
한 가지주의 사항 : Java 8의 Math.floorMod ()와 달리 제수 (두 번째 매개 변수)는 음수가 될 수 없습니다.
수 이론에서 결과는 항상 양수입니다. 모든 프로그래머가 수학자는 아니기 때문에 컴퓨터 언어에서는 이것이 항상 그런 것은 아니라고 생각합니다. 내 두 센트, 나는 그것을 언어의 디자인 결함이라고 생각하지만 지금은 바꿀 수 없습니다.
= 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
은 여기의 다른 답변과 같지만 조건부 분기가없고 느린 작업이 하나뿐입니다 %
.
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
아닌 정확한 모드 연산자를하고 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의 전체 범위에서 임의적이면 두 솔루션의 분포는 동일합니다. 입력 클러스터가 0에 가까우 n - 1
면 후자의 솔루션에서 결과가 너무 적습니다 .
다음은 대안입니다.
a < 0 ? b-1 - (-a-1) % b : a % b
이것은 다른 공식 [(a % b + b) % b]보다 빠르거나 빠르지 않을 수 있습니다. 다른 공식과 달리 분기를 포함하지만 모듈로 연산을 하나 덜 사용합니다. 컴퓨터가 <0을 정확하게 예측할 수 있다면 아마도 이길 것입니다.
(편집 : 수식을 수정했습니다.)