Java의 모듈러스가 음수로 작동하도록하는 가장 좋은 방법은 무엇입니까?


103

자바에서 할 때

a % b

a가 음수이면 b로 감싸는 대신 부정적인 결과를 반환합니다. 이 문제를 해결하는 가장 좋은 방법은 무엇입니까? 내가 생각할 수있는 유일한 방법은

a < 0 ? b + a : a % b

12
음수를 다룰 때 "올바른"계수 동작은 없습니다. 많은 언어에서 이런 방식으로 수행하고 많은 언어에서 다르게 수행하며 일부 언어에서는 완전히 다른 작업을 수행합니다. 적어도 처음 두 사람은 장단점이 있습니다.

4
이것은 나에게 이상합니다. b가 음수 일 때만 음수를 반환해야한다고 생각했습니다.
fent


2
그것은. 그러나 해당 질문의 제목은 변경해야합니다. Java 모듈러스가 어떻게 작동하는지 이미 알고 있기 때문에이 질문을 검색하는 경우 해당 질문을 클릭하지 않을 것입니다.
fent

4
저는 "왜 -13 % 64 = 51입니까?"라는 이름으로 이름을 바꿨습니다. 이것은 백만 년 안에 누군가가 검색 할 수있는 어떤 것도 아닙니다. 따라서이 질문 제목은 모듈러스, 음수, 계산, 숫자와 같은 키워드에서 훨씬 더 좋고 검색 가능성이 훨씬 더 높습니다.
Erick Robertson

답변:


144

a % b = a-a / b * b; 즉, 나머지입니다.

할 수 있습니다 (a % b + b) % b


이 표현식은 결과 가 양수인지 음수 인지 에 관계없이 (a % b)반드시이보다 낮기 때문에 작동합니다 . 이 추가 의 음의 값을 담당 하기 때문에, 사이의 네거티브 값이 과 , 반드시 하부보다 긍정적. 마지막 모듈은 경우가 이후 경우,로 시작하는 긍정적 긍정적 보다 크게 될 것이다 . 따라서 다시 더 작게 만듭니다 ( 음수 값 에는 영향을주지 않음 ).baba(a % b)-b0(a % b + b)baa(a % b + b)b(a % b + b) % bba


3
감사합니다. b보다 훨씬 큰 음수에도 작동합니다.
fent

6
이는 이후의 결과 일 (a % b)필요는보다 낮은 bIF (아무리 a추가하면, 포지티브 또는 네거티브) b의 음의 값을 담당 a하기 때문에, (a % b)보다 낮은 b그리고보다 낮은 0, (a % b + b)반드시 미만 b긍정적. 마지막 모듈은 경우가 a이후 경우,로 시작하는 긍정적 a긍정적 (a % b + b)보다 크게 될 것이다 b. 따라서 다시 (a % b + b) % b더 작게 만듭니다 ( b음수 a값 에는 영향을주지 않음 ).
ethanfar

1
내가 대답에 당신의 훌륭한 설명이 포함했습니다 @eitanfar (에 대한 약간의 수정과를 a < 0, 어쩌면 당신은 좀 가질 수)
마틴 Bodewes

5
나는 방금 동일한 주제에 관한 다른 질문에 대한 주석을 보았다. 및의 (a % b + b) % b매우 큰 값에 대해 분류된다는 점을 언급 할 가치가 있습니다 . 예를 들어, and will give as result, which is the negative number, which is what you want to avoid. aba = Integer.MAX_VALUE - 1b = Integer.MAX_VALUE-3
Thorbear 2015-09-16

2
a를 사용하는 @Mikepote while는 실제로 필요한 경우를 제외하고 실제로 필요한 경우 더 느릴 if것입니다.
피터 Lawrey

92

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

1
8 + 자바에 대한 가장 좋은 대답
차니 케이

멋져요, 그거 몰랐어요. Java 8은 몇 가지 PITA를 확실히 수정했습니다.
Franz D.

4
좋은 방법입니다. 그러나 불행히도 float또는 double논쟁 과 함께 작동하지 않습니다 . Mod 이항 연산자 ( %)는 floatdouble피연산자 와 함께 작동합니다 .
Mir-Ismaili

11

아직 Java 8을 사용하지 않거나 사용할 수없는 사람들을 위해 Guava는 Guava 11.0부터 사용할 수 있는 IntMath.mod () 를 사용 하여 구출했습니다 .

IntMath.mod( 2, 3) = 2
IntMath.mod(-2, 3) = 1

한 가지주의 사항 : Java 8의 Math.floorMod ()와 달리 제수 (두 번째 매개 변수)는 음수가 될 수 없습니다.


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 분이라고 말할 것입니다.


1
숫자 이론에서 항상 긍정적 인 것은 아닙니다 ... 그들은 합동 클래스에 속합니다. 표기 목적으로 해당 클래스의 후보를 자유롭게 선택할 수 있지만, 모든 클래스에 매핑된다는 아이디어가 있으며 특정 다른 후보를 사용하면 특정 문제가 훨씬 더 간단 해집니다 ( 예를 들어 -1대신 선택 n-1). 그런 다음 그것을 가지고 있습니다.
BeUndead

2

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아닌 정확한 모드 연산자를하고 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면 후자의 솔루션에서 결과가 너무 적습니다 .


1

다음은 대안입니다.

a < 0 ? b-1 - (-a-1) % b : a % b

이것은 다른 공식 [(a % b + b) % b]보다 빠르거나 빠르지 않을 수 있습니다. 다른 공식과 달리 분기를 포함하지만 모듈로 연산을 하나 덜 사용합니다. 컴퓨터가 <0을 정확하게 예측할 수 있다면 아마도 이길 것입니다.

(편집 : 수식을 수정했습니다.)


1
그러나 모듈로 연산에는 훨씬 더 느릴 수있는 분할이 필요합니다 (특히 프로세서가 거의 항상 분기를 정확하게 추측하는 경우). 그래서 이것은 아마도 더 낫습니다.
데이브

@KarstenR. 당신이 맞아요! 수식을 수정 했으므로 이제는 잘 작동하지만 두 개의 빼기가 더 필요합니다.
Stefan Reich

맞습니다 @dave
Stefan Reich
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.