음수로 모듈로 연산


195

C 프로그램에서 나는 아래 작업을 시도하고 있었다 (동작을 확인하기 위해)

 x = 5 % (-3);
 y = (-5) % (3);
 z = (-5) % (-3); 

printf("%d ,%d ,%d", x, y, z); 

(2, -2 , -2)gcc에서 와 같이 출력을주었습니다 . 나는 매번 긍정적 인 결과를 기대하고있었습니다. 계수가 음수 일 수 있습니까? 아무도이 행동을 설명 할 수 있습니까?



답변:


170

C99 는 다음과 같이 표현할 수 있어야 합니다 a/b.

(a/b) * b + a%b 는 같을 것이다a

논리적으로 말이됩니다. 권리?

이것이 무엇으로 연결되는지 봅시다 :


예 A. 5/(-3)-1

=> (-1) * (-3) + 5%(-3) =5

5%(-3)2 인 경우에만 발생할 수 있습니다 .


예 B. (-5)/3-1

=> (-1) * 3 + (-5)%3 =-5

경우에만 발생할 수 (-5)%3있다-2


1
컴파일러가 충분히 똑똑하고 부호없는 모듈로 부호없는 모듈로가 항상 양수임을 감지해야합니까? 현재 (GCC 5.2) 컴파일러는 두 피연산자가 모두 uint32_t 이상인 경우에도 "%"가 "unsigned"가 아니라 "int"를 반환한다고 생각하는 것 같습니다.
Frederick Nord

@FrederickNord 그 행동 을 보여주는 예가 있습니까?
chux-복직 모니카

10
설명하는 것은 mod에 대한 일반적인 int (a / b) (잘라 내기) 설명입니다. 그러나 규칙이 바닥 (a / b) (Knuth) 일 수도 있습니다. Knuth의 경우 -5/3-2이고 mod는 1이됩니다. 한 모듈은 피제수 부호 (잘라 내기) 뒤에 오는 부호를 가지며, 다른 모듈에는 제수 부호 (Knuth) 뒤에 오는 부호가 있습니다.
Isaac Isaac

1
이것은 C 표준이 내가 원하는 것이 아닌 경우입니다. 나는 0 또는 음의 모듈로 숫자로 자르기를 원하지 않았지만 종종 반대를 원하며 C 주위에서 작동해야합니다.
Joe

144

%C 의 연산자는 모듈로 연산자가 아니라 나머지 연산자입니다.

모듈로 및 나머지 연산자는 음수 값이 다릅니다.

나머지 연산자의 경우 결과의 부호는 피제수의 부호와 같지만 모듈러스 연산자의 경우 결과의 부호는 제수와 같습니다.

C는 다음 과 같이 %작업을 정의합니다 a % b.

  a == (a / b * b) + a % b

/향해 정수 나누기를 사용 0합니다. 그것은 모듈로 연산자가 아닌 나머지 연산자로 0정의하는 (음의 무한대가 아닌)쪽으로 수행되는 잘림입니다 %.


8
나머지는 정의에 의한 모듈로 연산의 결과입니다 . 나머지 연산과 같은 것이 없기 때문에 나머지 연산자와 같은 것은 없어야합니다.이를 모듈로라고합니다.
gronostaj 2016 년

41
CS에없는 @gronostaj. Haskell 또는 Scheme과 같은 두 가지 다른 연산자 ( remaindermoduloScheme remmodHaskell)를 정의하는 고급 언어를 살펴보십시오 . 이러한 연산자 사양은 나누기가 수행되는 방식에 따라 언어가 다릅니다. 0으로 자르거나 음의 무한대로 자릅니다. 는 C 표준은 결코 호출되지 그런데 모듈로 연산자를 , 그들은 단지 그것을 이름 % 연산자를 . %
ouah December

2
C 의 remainder 기능 과 혼동하지 말아야합니다.이 부분에서 IEEE 나머지를 반올림하여 의미론을 구현합니다
Eric

68

C99 사양을 기반으로 : a == (a / b) * b + a % b

계산할 함수를 작성할 수 있습니다 (a % b) == a - (a / b) * b!

int remainder(int a, int b)
{
    return a - (a / b) * b;
}

모듈로 연산의 경우 다음과 같은 기능을 가질 수 있습니다 (가정 b > 0)

int mod(int a, int b)
{
    int r = a % b;
    return r < 0 ? r + b : r;
}

내 결론은 a % bC에서 나머지 연산이며 모듈로 연산 이 아니라는 것 입니다.


3
때 긍정적 인 결과를 제공하지 않습니다 b(그리고에 대한 사실 음수 rb는 결과보다주는 모두 부정적 -b). 사용할 수있는 모든 입력에 대해 긍정적 인 결과를 얻 r + abs(b)거나 b부호 를 일치 시키기 위해 r*b < 0대신 조건을 변경할 수 있습니다 .
마틴 엔더

@MartinEnder r + abs(b)는 UB b == INT_MIN입니다.
chux-복원 Monica Monica

60

나는 숫자가 음수인지 확인할 필요가 없다고 생각합니다.

포지티브 모듈로를 찾는 간단한 함수는 다음과 같습니다.

편집 : 가정 N > 0N + N - 1 <= INT_MAX

int modulo(int x,int N){
    return (x % N + N) %N;
}

이것은 x의 양수과 음수모두에 적용 됩니다 .

원래 추신 : 또한 @chux가 가리키는 아웃으로, 귀하의 x와 N은 대체 각각 INT_MAX-1 및 INT_MAX 같은 도달 할 수있는 경우 intlong long int.

그리고 그들이 오랫동안 긴 한계를 넘어 서면 (즉, LLONG_MAX 근처), 당신은 여기에 다른 답변에서 설명 된 것처럼 긍정적이고 부정적인 경우를 별도로 처리해야합니다.


1
일 때 N < 0와 같이 결과는 음수 일 수 있습니다 modulo(7, -3) --> -2. 또한 정의되지 않은 동작 인 수학을 x % N + N오버플로 할 수 있습니다 int. 예를 들어 modulo(INT_MAX - 1,INT_MAX)-3이 될 수 있습니다.
chux-복원 Monica Monica

예.이 경우 간단히을 사용 long long int하거나 음수를 별도로 처리 할 수 있습니다 (단순성을 잃는 대신).
Udayraj Deshmukh

9

다른 답변은 C99 이상 에서 설명 했으므로 음의 피연산자를 포함하는 정수 나누기는 항상 0으로 잘립니다 .

C89에서 , 결과가 상향 또는 하향으로 반올림되는지는 구현-정의 됨에 유의한다 . 모든 표준에서 (a/b) * b + a%b동일 하기 때문에 음의 피연산자가 포함 a된 결과 %도 C89에 구현 정의되어 있습니다.


5

계수가 음수 일 수 있습니까?

%Euclidean_division 이후 가 아니라 나머지 연산자 인 나머지 나눗셈이므로 음수 일 수 있습니다 . C99이므로 결과는 0, 음수 또는 양수일 수 있습니다.

 // a % b
 7 %  3 -->  1  
 7 % -3 -->  1  
-7 %  3 --> -1  
-7 % -3 --> -1  

모듈로 원 영업 이익은 고전적인 유클리드 모듈로 하지 %.

나는 매번 긍정적 인 결과를 기대하고있었습니다.

때마다 잘 정의 된 유클리드 모듈로 수행하려면 a/b정의를, a,b어떤 부호이며, 결과는 부정적인 결코 :

int modulo_Euclidean(int a, int b) {
  int m = a % b;
  if (m < 0) {
    // m += (b < 0) ? -b : b; // avoid this form: it is UB when b == INT_MIN
    m = (b < 0) ? m - b : m + b;
  }
  return m;
}

modulo_Euclidean( 7,  3) -->  1  
modulo_Euclidean( 7, -3) -->  1  
modulo_Euclidean(-7,  3) -->  2  
modulo_Euclidean(-7, -3) -->  2   

2

모듈로 연산의 결과는 분자의 부호에 따라 다르므로 yz에 대해 -2를 얻습니다.

여기 참조입니다

http://www.chemie.fu-berlin.de/chemnet/use/info/libc/libc_14.html

정수 부서

이 섹션에서는 정수 나누기를 수행하는 기능에 대해 설명합니다. GNU C에서는 '/'연산자가 항상 0으로 반올림하기 때문에 이러한 함수는 GNU C 라이브러리에서 중복됩니다. 그러나 다른 C 구현에서 '/'는 음수 인수로 다르게 반올림 될 수 있습니다. div와 ldiv는 몫을 반올림하는 방법을 지정하기 때문에 유용합니다. 나머지는 분자와 같은 부호를 갖습니다.


5
ANSI C에 대한 텍스트를 참조하고 있습니다. 이는 상당히 오래된 C 표준입니다. 텍스트가 ANSI C와 관련하여 정확한지 확실하지 않지만 C99와 관련하여 확실하지 않은지 확실하지 않습니다. C99 §6.5.5에서 정수 나누기는 항상 0쪽으로 잘 리도록 정의됩니다.
Palec

2

이러한 관습에서 비롯된 수학에서는 모듈로 산술이 긍정적 인 결과를 가져야한다는 주장이 없습니다.

예 :

1 mod 5 = 1이지만 -4와 같을 수도 있습니다. 즉, 1/5는 0에서 나머지 1을, 5에서 -4를 산출합니다. (두 요인 모두 5)

마찬가지로, -1 mod 5 = -1이지만 4 와도 같을 수 있습니다. 즉, -1/5는 0에서 나머지 -1을, -5에서 4를 산출합니다. (5 가지 요소)

더 읽기 위해 수학의 등가 수업 을 살펴보십시오 .


동등성 클래스는 다른 개념이며 모듈로는 매우 엄격한 방식으로 정의됩니다. 이제 우리는 두 개의 정수 번호를 가지고 있다고 가정 해 봅시다 ab, b <> 0. 유클리드 부문의 정리에 따르면 정수 정확히 한 쌍의 존재 m, 과 . 상기 는 (수학적) 모듈로 연산의 결과이며, 정의상 음이 아니다. Wikipedia에 대한 더 많은 정보와 추가 링크 : en.wikipedia.org/wiki/Euclidean_divisionra = m * b + r0 <= r < abs( b )r
Ister

사실이 아닙니다. 1 mod 5항상 1입니다. 1 -4 mod 5일 수도 있지만 다른 것입니다.
FelipeC

2

에 따르면 C99 표준 , 섹션 6.5.5 곱셈 연산자는 다음이 필요합니다 :

(a / b) * b + a % b = a

결론

C99에 따르면 나머지 작업의 결과는 배당과 동일합니다.

몇 가지 예를 보자 ( dividend / divisor) :

배당금 만 마이너스 인 경우

(-3 / 2) * 2  +  -3 % 2 = -3

(-3 / 2) * 2 = -2

(-3 % 2) must be -1

제수 만 음수 인 경우

(3 / -2) * -2  +  3 % -2 = 3

(3 / -2) * -2 = 2

(3 % -2) must be 1

제수와 배당이 모두 음수 일 때

(-3 / -2) * -2  +  -3 % -2 = -3

(-3 / -2) * -2 = -2

(-3 % -2) must be -1

6.5.5 곱하기 연산자

통사론

  1. 곱셈식 :
    • cast-expression
    • multiplicative-expression * cast-expression
    • multiplicative-expression / cast-expression
    • multiplicative-expression % cast-expression

제약

  1. 각 피연산자는 산술 유형을 가져야합니다. % 연산자 의 피연산자 는 정수 유형이어야합니다.

의미론

  1. 일반적인 산술 변환은 피연산자에서 수행됩니다.

  2. 이항 * 연산자 의 결과 는 피연산자의 곱입니다.

  3. / 연산자 의 결과는 첫 번째 피연산자를 두 번째 피연산자로 나눈 몫입니다. % 연산자 의 결과 는 나머지입니다. 두 연산에서 두 번째 피연산자의 값이 0이면 동작이 정의되지 않습니다.

  4. 정수를 나누면 / 연산자 의 결과는 분수 부분을 버린 대수 몫입니다 [1]. 몫 a/b이 표현 가능한 경우, 표현은 (a/b)*b + a%b같다 a.

[1] : 이것을 "0으로 자르기"라고합니다.


1

모듈러스 연산자가 나머지를 제공합니다. c의 계수 연산자는 일반적으로 분자의 부호를 갖습니다.

  1. x = 5 % (-3)-분자는 양이므로 2가됩니다
  2. y = (-5) % (3)-여기서 분자는 음수이므로 결과는 -2입니다.
  3. z = (-5) % (-3)-여기서 분자는 음수이므로 결과는 -2

또한 modulus (remainder) 연산자는 정수 유형에만 사용할 수 있으며 부동 소수점에는 사용할 수 없습니다.


2
외부 리소스에 대한 링크로 이것을 백업 할 수 있다면 좋을 것입니다.
J ... S

1

mod추상적 산술에 정의 된대로 생각하는 것이 더 유용하다고 생각합니다 . 연산이 아니라 요소와 연산자가 다른 완전히 다른 산술 클래스입니다. 즉, 추가 mod 3는 "정상"추가와 동일하지 않습니다. 그건; 정수 추가.

따라서 할 때 :

5 % -3

정수 5를의 집합에있는 요소에 매핑하려고합니다 mod -3. 이들은 다음의 요소입니다 mod -3.

{ 0, -2, -1 }

그래서:

0 => 0, 1 => -2, 2 => -1, 3 => 0, 4 => -2, 5 => -1

어떤 이유로 30 시간을 유지해야한다고하자. 30 mod -24.

그러나 C가 구현하는 것은 아닙니다 mod. 어쨌든 요점은 부정적인 것을 반환하는 것이 합리적이라는 것입니다.

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