C # 정수 산술에서 a / b / c는 항상 a / (b * c)와 같습니까?


81

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에 대해합니까?


3
이것은 프로그래밍 문제가 아니라 수학 문제입니다. 이 질문의 프로그래밍 특정 부분이 무엇인지 설명 할 수 있습니까?
Oded

38
@Oded는 모든 유리수의 범위에 있지만, 이것은 특히 정수 산술 (C #에서)을 의미합니다. 프로그래밍과 관련된 IMO. 아마도 a / b / c == a / (b * c)가 정수 산술에서 유지하는 규칙 일 수도 있고, 유리수 산술에서만 유지 될 수도 있습니다.
Tim S.

43
이것은 C #에 대한 완벽하게 합리적인 질문이며 대답하기 쉽습니다.
Eric Lippert 2013 년

12
@Oded 이것은 컴퓨터 산술과 그것이 순수 수학과 동일하게 작동하는지에 대한 질문입니다. 닫히면 안됩니다.
Jeffrey Sax 2013 년

4
나는 오버플로를 무시하고 왜 (또는 실제로 그럴 것인지) 수학적 증명에 상당히 관심이있을 것이다.이 둘은 사실상 동등하지만 아직 하나를 합치 지 못했다.
Rawling 2013 년

답변:


71

하자 \나타낸다 정수 나누기 (는 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]는 다음과 같이 설명됩니다. 범위에 두 개의 정수 ab소수 가 있다고 가정합니다 . 그것을 보는 것은 간단합니다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의 답변을 참조하십시오! 그는 또한 그의 블로그 게시물 과 답변 에서 훨씬 더 엄격한 접근 방식을 취합니다 .


1
Hah, 그게 내가
추구

나는 이것을 위해 \ 및 /를 사용하는 것이 좋습니다. 상황을 훨씬 더 명확하게합니다.
Justin Morgan

@JustinMorgan이 표기법은 실제로 다른 프로그래밍 언어에서 사용됩니다 (현재 어떤 언어인지는 기억 나지 않지만).
Timothy Shields 2013 년

1
@TimothyShields VB.net은 그렇습니다.
Arie Xiao

주장이 사실이라고 생각하지만 귀하의 증거에 핵심 단계가 누락 된 것 같습니다. 2 행 => 3 행에 대한 귀하의 정당성을 오해했을 가능성이 있습니다. 내가 해석 한 방식 floor(x / y) - (x / y)은 작기 z >= 1때문에 floor0을 취하면 무시할 수 있습니다. 실제로는 내부의 추가 항목이므로 실제로 따르지 않습니다 floor()(예 : floor(1/2)vs 고려 floor(1/2 + 1/2)).
rliu

77

나는이 질문을 너무 좋아해서 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 < c0 <= 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.


7
예 @JoseRuiSantos하지만, 모두 x1 x2 작업은이 경우에 동일하게 충돌합니다
마크 Gravell

@JoseRuiSantos는 두 경우 모두 사실이 아닙니까?
Jodrell 2013 년

vc 74의 답변이 삭제되었으므로 대부분의 사람들은 더 이상 참조하는 예제를 볼 수 없습니다.
Gabe 2013 년

맞습니다, 모두 x1x2경우 충돌합니다 b또는 c제로입니다. 다른 값의 x1경우 가능한 정수 오버플로 ( b * c)를 피할 수 있으므로 표현식이 더 좋습니다 x2.
Jose Rui Santos

오버플로 및 확인 된 산술에 대한 흥미로운 점, 감사합니다!
Jason Crease 2013 년

4

b및 의 절대 값이 csqrt(2^31)(약 46300) 미만 이면 b * c오버플로되지 않으므로 값은 항상 일치합니다. 경우 b * c오버 플로우, 다음 오류가에 던져 질 수있는 checked상황, 또는 당신은에 잘못된 값이 얻을 수있는 unchecked상황을.


2

다른 사람들이 발견 한 오버플로 오류를 피하면 항상 일치합니다.

의가 있다고 가정하자 a/b=q1,하는 수단이 a=b*q1+r10<=r1<b.
이제을 가정 a/b/c=q2것을 의미하는 q1=c*q2+r20<=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음수 이면 작동하지 않지만 그 경우에도 정수 나눗셈이 어떻게 작동하는지 모르겠습니다.


0

나는 재미로 내 자신의 증거를 제공 할 것입니다. 이것은 또한 오버플로를 무시하고 불행히도 긍정 만 처리하지만 증거가 깨끗하고 명확하다고 생각합니다.

목표는

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 < zr1은 정수이므로 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.

위의 증명은 추가 사례를 확인하는 데 필요한 몇 단계를 제외하고는 네거티브와 함께 작동해야하지만 확인하지 않았습니다.


0

카운터 예 : INT_MIN / -1/2


"a, b 및 c는 크지 않은 양의 정수가되게하십시오."
Pang

흥미로운 경우입니다 (예 : -INT_MIN은 오버플로 임). 감사!
Jason Crease
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.