C 프로그램에서 나는 아래 작업을 시도하고 있었다 (동작을 확인하기 위해)
x = 5 % (-3);
y = (-5) % (3);
z = (-5) % (-3);
printf("%d ,%d ,%d", x, y, z);
(2, -2 , -2)
gcc에서 와 같이 출력을주었습니다 . 나는 매번 긍정적 인 결과를 기대하고있었습니다. 계수가 음수 일 수 있습니까? 아무도이 행동을 설명 할 수 있습니까?
C 프로그램에서 나는 아래 작업을 시도하고 있었다 (동작을 확인하기 위해)
x = 5 % (-3);
y = (-5) % (3);
z = (-5) % (-3);
printf("%d ,%d ,%d", x, y, z);
(2, -2 , -2)
gcc에서 와 같이 출력을주었습니다 . 나는 매번 긍정적 인 결과를 기대하고있었습니다. 계수가 음수 일 수 있습니까? 아무도이 행동을 설명 할 수 있습니까?
답변:
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
-5/3
는 -2
이고 mod는 1이됩니다. 한 모듈은 피제수 부호 (잘라 내기) 뒤에 오는 부호를 가지며, 다른 모듈에는 제수 부호 (Knuth) 뒤에 오는 부호가 있습니다.
%
C 의 연산자는 모듈로 연산자가 아니라 나머지 연산자입니다.
모듈로 및 나머지 연산자는 음수 값이 다릅니다.
나머지 연산자의 경우 결과의 부호는 피제수의 부호와 같지만 모듈러스 연산자의 경우 결과의 부호는 제수와 같습니다.
C는 다음 과 같이 %
작업을 정의합니다 a % b
.
a == (a / b * b) + a % b
를 /
향해 정수 나누기를 사용 0
합니다. 그것은 모듈로 연산자가 아닌 나머지 연산자로 0
정의하는 (음의 무한대가 아닌)쪽으로 수행되는 잘림입니다 %
.
remainder
및 modulo
Scheme rem
및 mod
Haskell)를 정의하는 고급 언어를 살펴보십시오 . 이러한 연산자 사양은 나누기가 수행되는 방식에 따라 언어가 다릅니다. 0으로 자르거나 음의 무한대로 자릅니다. 는 C 표준은 결코 호출되지 그런데 모듈로 연산자를 , 그들은 단지 그것을 이름 % 연산자를 . %
remainder
기능 과 혼동하지 말아야합니다.이 부분에서 IEEE 나머지를 반올림하여 의미론을 구현합니다
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 % b
C에서 나머지 연산이며 모듈로 연산 이 아니라는 것 입니다.
b
(그리고에 대한 사실 음수 r
와 b
는 결과보다주는 모두 부정적 -b
). 사용할 수있는 모든 입력에 대해 긍정적 인 결과를 얻 r + abs(b)
거나 b
부호 를 일치 시키기 위해 r*b < 0
대신 조건을 변경할 수 있습니다 .
r + abs(b)
는 UB b == INT_MIN
입니다.
나는 숫자가 음수인지 확인할 필요가 없다고 생각합니다.
포지티브 모듈로를 찾는 간단한 함수는 다음과 같습니다.
편집 : 가정 N > 0
및N + N - 1 <= INT_MAX
int modulo(int x,int N){
return (x % N + N) %N;
}
이것은 x의 양수 값 과 음수 값 모두에 적용 됩니다 .
원래 추신 : 또한 @chux가 가리키는 아웃으로, 귀하의 x와 N은 대체 각각 INT_MAX-1 및 INT_MAX 같은 도달 할 수있는 경우 int
에 long long int
.
그리고 그들이 오랫동안 긴 한계를 넘어 서면 (즉, LLONG_MAX 근처), 당신은 여기에 다른 답변에서 설명 된 것처럼 긍정적이고 부정적인 경우를 별도로 처리해야합니다.
N < 0
와 같이 결과는 음수 일 수 있습니다 modulo(7, -3) --> -2
. 또한 정의되지 않은 동작 인 수학을 x % N + N
오버플로 할 수 있습니다 int
. 예를 들어 modulo(INT_MAX - 1,INT_MAX)
-3이 될 수 있습니다.
long long int
하거나 음수를 별도로 처리 할 수 있습니다 (단순성을 잃는 대신).
계수가 음수 일 수 있습니까?
%
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
모듈로 연산의 결과는 분자의 부호에 따라 다르므로 y 와 z에 대해 -2를 얻습니다.
여기 참조입니다
http://www.chemie.fu-berlin.de/chemnet/use/info/libc/libc_14.html
정수 부서
이 섹션에서는 정수 나누기를 수행하는 기능에 대해 설명합니다. GNU C에서는 '/'연산자가 항상 0으로 반올림하기 때문에 이러한 함수는 GNU C 라이브러리에서 중복됩니다. 그러나 다른 C 구현에서 '/'는 음수 인수로 다르게 반올림 될 수 있습니다. div와 ldiv는 몫을 반올림하는 방법을 지정하기 때문에 유용합니다. 나머지는 분자와 같은 부호를 갖습니다.
이러한 관습에서 비롯된 수학에서는 모듈로 산술이 긍정적 인 결과를 가져야한다는 주장이 없습니다.
예 :
1 mod 5 = 1이지만 -4와 같을 수도 있습니다. 즉, 1/5는 0에서 나머지 1을, 5에서 -4를 산출합니다. (두 요인 모두 5)
마찬가지로, -1 mod 5 = -1이지만 4 와도 같을 수 있습니다. 즉, -1/5는 0에서 나머지 -1을, -5에서 4를 산출합니다. (5 가지 요소)
더 읽기 위해 수학의 등가 수업 을 살펴보십시오 .
a
와 b
, b <> 0
. 유클리드 부문의 정리에 따르면 정수 정확히 한 쌍의 존재 m
, 과 . 상기 는 (수학적) 모듈로 연산의 결과이며, 정의상 음이 아니다. Wikipedia에 대한 더 많은 정보와 추가 링크 : en.wikipedia.org/wiki/Euclidean_divisionr
a = m * b + r
0 <= r < abs( b )
r
1 mod 5
항상 1입니다. 1 -4 mod 5
일 수도 있지만 다른 것입니다.
에 따르면 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 곱하기 연산자
통사론
- 곱셈식 :
cast-expression
multiplicative-expression * cast-expression
multiplicative-expression / cast-expression
multiplicative-expression % cast-expression
제약
- 각 피연산자는 산술 유형을 가져야합니다. % 연산자 의 피연산자 는 정수 유형이어야합니다.
의미론
일반적인 산술 변환은 피연산자에서 수행됩니다.
이항 * 연산자 의 결과 는 피연산자의 곱입니다.
/ 연산자 의 결과는 첫 번째 피연산자를 두 번째 피연산자로 나눈 몫입니다. % 연산자 의 결과 는 나머지입니다. 두 연산에서 두 번째 피연산자의 값이 0이면 동작이 정의되지 않습니다.
정수를 나누면 / 연산자 의 결과는 분수 부분을 버린 대수 몫입니다 [1]. 몫
a/b
이 표현 가능한 경우, 표현은(a/b)*b + a%b
같다a
.[1] : 이것을 "0으로 자르기"라고합니다.
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
. 어쨌든 요점은 부정적인 것을 반환하는 것이 합리적이라는 것입니다.