a, b 및 c를 크지 않은 양의 정수라고합시다. a / b / c는 C # 정수 산술에서 항상 a / (b * c)와 같습니까? 나를 위해 C #에서는 다음과 같이 보입니다.
int a = 5126, b = 76, c = 14;
int x1 = a / b / c;
int x2 = a / (b * c);
그래서 내 질문은 : x1 == x2모든 a, b 및 c에 대해합니까?
a, b 및 c를 크지 않은 양의 정수라고합시다. a / b / c는 C # 정수 산술에서 항상 a / (b * c)와 같습니까? 나를 위해 C #에서는 다음과 같이 보입니다.
int a = 5126, b = 76, c = 14;
int x1 = a / b / c;
int x2 = a / (b * c);
그래서 내 질문은 : x1 == x2모든 a, b 및 c에 대해합니까?
답변:
하자 \나타낸다 정수 나누기 (는 C #의 /둘 사이의 운영자 int들) 및하자 /나타낸다 보통 수학 부문. 그런 경우 x,y,z입니다 양의 정수가 우리가하는 오버 플로우를 무시하고 ,
(x \ y) \ z
= floor(floor(x / y) / z) [1]
= floor((x / y) / z) [2]
= floor(x / (y * z))
= x \ (y * z)
어디
a \ b = floor(a / b)
위의 행에서 행 [1]으로 의 점프 [2]는 다음과 같이 설명됩니다. 범위에 두 개의 정수 a와 b소수 가 있다고 가정합니다 . 그것을 보는 것은 간단합니다f[0, 1)
floor(a / b) = floor((a + f) / b) [3]
줄 경우 [1]를 식별 a = floor(x / y), f = (x / y) - floor(x / y)그리고 b = z, 다음 [3]것을 의미 [1]와 [2]동일하다.
이 증명을 음의 정수로 일반화 할 수 있지만 (여전히 overflow 무시 ), 요점을 간단하게 유지하기 위해 독자에게 맡기겠습니다.
오버플로 문제에 대해 -좋은 설명은 Eric Lippert의 답변을 참조하십시오! 그는 또한 그의 블로그 게시물 과 답변 에서 훨씬 더 엄격한 접근 방식을 취합니다 .
floor(x / y) - (x / y)은 작기 z >= 1때문에 floor0을 취하면 무시할 수 있습니다. 실제로는 내부의 추가 항목이므로 실제로 따르지 않습니다 floor()(예 : floor(1/2)vs 고려 floor(1/2 + 1/2)).
나는이 질문을 너무 좋아해서 2013 년 6 월 4 일에 내 블로그 의 주제로 삼았습니다 . 좋은 질문에 감사드립니다!
큰 케이스는 쉽게 구할 수 있습니다. 예를 들면 :
a = 1073741823;
b = 134217727;
c = 134217727;
b * c음수로 넘치기 때문 입니다.
나는에이 사실 것을 추가 할 산술 검사가 , 차이 a / (b * c)와이 (a / b) / c프로그램의 차이가 될 수있는 작품과 프로그램 충돌이. 의 제품 경우 b와는 c정수의 경계를 오버 플로우 한 후 전자는 확인 맥락에서 충돌합니다.
작은 양의 정수, 예를 들어 짧은 값에 들어갈 수있을만큼 작은 경우, 동일성은 유지되어야합니다.
Timothy Shields는 방금 증거를 게시했습니다. 여기에 대체 증거를 제시합니다. 여기에있는 모든 숫자가 음이 아닌 정수이고 작업이 오버플로되지 않는다고 가정합니다.
정수 분할 x / y찾은 값이 q되도록 q * y + r == x, 여기서 0 <= r < y.
따라서 부서 a / (b * c)는 다음 q1과 같은 값을 찾습니다.
q1 * b * c + r1 == a
어디 0 <= r1 < b * c
부서는 ( a / b ) / c먼저 다음 qt과 같은 값을 찾습니다.
qt * b + r3 == a
그런 다음 다음 q2과 같은 값을 찾습니다.
q2 * c + r2 == qt
그래서 그것을로 대체 qt하면 다음과 같이됩니다.
q2 * b * c + b * r2 + r3 == a
어디 0 <= r2 < c와 0 <= r3 < b.
동일한 두 가지가 서로 동일하므로
q1 * b * c + r1 == q2 * b * c + b * r2 + r3
q1 == q2 + x정수 라고 가정 합니다 x. 그것을 대체하고 다음을 해결하십시오 x.
q2 * b * c + x * b * c + r1 = q2 * b * c + b * r2 + r3
x = (b * r2 + r3 - r1) / (b * c)
어디
0 <= r1 < b * c
0 <= r2 < c
0 <= r3 < b
x0보다 클 수 있습니까 ? 아닙니다. 우리에게는 불평등이 있습니다.
b * r2 + r3 - r1 <= b * r2 + r3 <= b * (c - 1) + r3 < b * (c - 1) + b == b * c
그래서 분수의 분자보다 항상 작은 b * c때문에, x0보다 클 수 없습니다.
x0보다 작을 수 있습니까 ? 아니, 비슷한 주장으로 독자에게 맡겼다.
따라서 정수 x는 0이므로 q1 == q2.
x1 와x2 작업은이 경우에 동일하게 충돌합니다
x1와 x2경우 충돌합니다 b또는 c제로입니다. 다른 값의 x1경우 가능한 정수 오버플로 ( b * c)를 피할 수 있으므로 표현식이 더 좋습니다 x2.
다른 사람들이 발견 한 오버플로 오류를 피하면 항상 일치합니다.
의가 있다고 가정하자 a/b=q1,하는 수단이 a=b*q1+r1곳 0<=r1<b.
이제을 가정 a/b/c=q2것을 의미하는 q1=c*q2+r2곳 0<=r2<c.
이것은 a=b(c*q2+r2)+r1=b*c*q2+br2+r1.
위해서는 a/(b*c)=a/b/c=q2, 우리는이 있어야합니다 0<=b*r2+r1<b*c.
그러나 b*r2+r1<b*r2+b=b*(r2+1)<=b*c필요에 따라 두 작업이 일치합니다.
이것은 음수 b이거나 c음수 이면 작동하지 않지만 그 경우에도 정수 나눗셈이 어떻게 작동하는지 모르겠습니다.
나는 재미로 내 자신의 증거를 제공 할 것입니다. 이것은 또한 오버플로를 무시하고 불행히도 긍정 만 처리하지만 증거가 깨끗하고 명확하다고 생각합니다.
목표는
floor(floor(x/y)/z) = floor(x/y/z)
/(이 증명을 통해) 정상적인 분할은 어디에 있습니까 ?
우리는 몫과 나머지를 다음과 같이 a/b 고유하게 나타냅니다 a = kb + r(이는 k,r고유하고 또한 참고 |r| < |b|). 그러면 다음이 있습니다.
(1) floor(x/y) = k => x = ky + r
(2) floor(floor(x/y)/r) = k1 => floor(x/y) = k1*z + r1
(3) floor(x/y/z) = k2 => x/y = k2*z + r2
그래서 우리의 목표는 단지 그것을 보여주는 것입니다 k1 == k2. 우리는 다음을 가지고 있습니다.
k1*z + r1 = floor(x/y) = k = (x-r)/y (from lines 1 and 2)
=> x/y - r/y = k1*z + r1 => x/y = k1*z + r1 + r/y
따라서:
(4) x/y = k1*z + r1 + r/y (from above)
x/y = k2*z + r2 (from line 3)
이제 r1정수 (for k1*z는 정의에 의한 정수)와 r1 < z(또한 정의에 의한 ) 정수인 (2)에서 관찰하십시오 . 또한 (1)에서 우리는 r < y => r/y < 1. 이제 r1 + r/y(4) 의 합계 를 고려하십시오 . 주장은 r1 + r/y < z이전 주장에서 명확합니다 (왜냐하면 0 <= r1 < z및 r1은 정수이므로 0 <= r1 <= z-1. 따라서 0 <= r1 + r/y < z). 따라서 r1 + r/y = r2정의에 의해 r2(그렇지 않으면 나머지 정의와 모순되는 두 개의 나머지 가있을 것 x/y입니다). 따라서 우리는 :
x/y = k1*z + r2
x/y = k2*z + r2
그리고 우리는 k1 = k2.
위의 증명은 추가 사례를 확인하는 데 필요한 몇 단계를 제외하고는 네거티브와 함께 작동해야하지만 확인하지 않았습니다.
카운터 예 : INT_MIN / -1/2