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
때문에 floor
0을 취하면 무시할 수 있습니다. 실제로는 내부의 추가 항목이므로 실제로 따르지 않습니다 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
x
0보다 클 수 있습니까 ? 아닙니다. 우리에게는 불평등이 있습니다.
b * r2 + r3 - r1 <= b * r2 + r3 <= b * (c - 1) + r3 < b * (c - 1) + b == b * c
그래서 분수의 분자보다 항상 작은 b * c
때문에, x
0보다 클 수 없습니다.
x
0보다 작을 수 있습니까 ? 아니, 비슷한 주장으로 독자에게 맡겼다.
따라서 정수 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