2012-04-10 1 views
0

은 당신이 논리와 같은 모드 작동을 대체 할 수있는 문서에 읽은왜 모듈러스 연산자가 필요합니까? 당신이 할</p> <pre><code>int Limit = Value % Range; </code></pre> <p>을 : 대신</p> <p>:

int Limit = Value & (Range-1); 

그러나 컴파일러는 여전히 모드 명령을 생성 내 질문은 기본적으로 : 컴파일러가 동일한 작업을 할 때 가장 효율적인 접근 방식을 사용하지 않는 이유는 무엇입니까?

+8

당신은 그 사람들이 어떻게 동일하다고 생각합니까? 예를 들어 해본 적이 있습니까? 음수로? – ildjarn

+3

... 또는 실제로 2 대 숫자가 아닌 모든 범위가 있습니까? – dmckee

+10

'&'는 * 논리적이고 * "* 아닙니다. –

답변

14

a = b % c; 

x = b % c; 
a = b/(x*c); 

와 함께 할 수있는 모듈없이 교체 초등 수학을 사용하여 2의 거듭 제곱 인 경우 만과 모듈로 대체 할 수는 이것을 확인 수 있습니다 예

25 % 7 = 
25/7 = 3 (integer math) 
25 - (3 * 7) = 
25 - 21 = 4 

어쨌든 내가 가지고 있지 않기 때문에 계산기에서 어떻게해야합니까? odulo 연산자.

25 & (7-6) = 
0x19 & 0x6 = 0x0 

그래서 대체가 작동하지 않습니다

참고.

대부분의 프로세서에는 모듈러가 없으며 대부분의 프로세서에는 분할이 없습니다. 해커의 기쁨을 확인해보십시오.

왜 모듈성을 원하십니까? 하드웨어를 구워 분할 할 경우, 모듈로 추가 할 수있는 여분의 마일을 기꺼이 사용할 수도 있습니다. 대부분의 프로세서는 여러분의 질문을 한단계 높여줍니다. 소프트웨어로 할 수있을 때 하드웨어로 나누는 이유는 무엇입니까? 귀하의 질문에 대한 답변은 대부분의 프로세서 제품군은 모듈러스가 없으며 소프트웨어 솔루션에 비해 칩 공간, 전력 소비 등 가치가 없기 때문에 많은 부분이 나누지 않습니다. 소프트웨어 솔루션은 고통스럽지 않거나 비용이 많이 들거나 위험합니다.

이제 우승 한 포스터가 귀하의 질문에 답변하지 않았다고 가정합니다. 범위가 2의 거듭 제곱이고 ID가 작동하는 경우 ... 범위가 컴파일 타임에 알려지지 않은 경우 먼저 빼기와 빼기, 두 연산, 그리고 중간 변수를 수행해야합니다. 모듈러스보다 훨씬 더 많은 비용이 들기 때문에 컴파일러는 모듈로 대신 뺄셈과를 사용하여 최적화 할 수 있습니다. 범위가 2의 제곱이고 컴파일 시간에 알려지면 더 나은/멋진 컴파일러가 최적화됩니다.가변 워드 길이 명령어 세트가있는 esp가 있는데, 더 작은 명령어가 큰 명령어에 대해 사용될 수 있고, Range를로드하고 더 많은 수의 0이 아닌 비트를로드하는 것보다 모듈러스가 덜 할 수 있습니다 (값은 귀하의 신원과 일치하는 범위는 값에 하나의 비트가 설정되고, 다른 비트는 0, 0x100, 0x40, 0x8000 등입니다.) 그리고 모듈로를 수행하십시오. 로드 바로 즉각 모듈러스는로드 직접 플러스보다 저렴할 수 있으며, 또는 모듈로 즉시 모듈은 즉시 모듈보다 저렴할 수 있습니다. 명령 세트와 컴파일러가 솔루션을 어떻게 구현했는지 조사해야합니다.

최적화를 수행하지 않는 부분의 예제를 게시하고 컴파일러가 예상 한 최적화를 수행 한 많은 예제를 게시 할 수 있다고 가정합니다.

+0

+1 내가 유권자의 초기 파를 그리워 늦게 답변을 할 수있는 최선입니다 ... 와우는 매우 좋은 explanation.Thank – Mysticial

+0

이었다! 나는 이것을 최선의 대답으로 고르고있다. D : – user1010005

+1

또 다른 의견은 모듈러스 명령어가 and 명령어보다 더 비싸다고 가정하지 않을 수도있다. 옛날에 예 그렇습니다. 모듈로 나누는 것은 더 많은 시계였습니다. 오늘날 반드시 그런 것은 아닙니다. 두 가지 방법으로 솔루션을 코딩하는 것은 어렵지 않습니다. 컴파일러가 컴파일러에서 수행 한 작업과 컴파일러가 수행하지 않은 작업의 차이점을 확인하십시오. –

26

음 ... 아니오 Range이 2의 거듭 제곱 인 경우에만 작동합니다.

다른 모든 값인 경우에도 여전히 모듈러스 % 연산자가 필요합니다.

음수로 작업 할 때 미묘한 차이 (구현에 따라 차이가있을 수 있음)도 있습니다.


보조 노트 : % 연산자를 사용하는 것이 더 읽기 쉬울 것입니다.

+1

가 널 최근에 그것을 사용하고 cool..And 지금 내가 바보 같은 느낌이라고 생각하고 감사'입니까? 내가 인해 사용'및'대신 2S의 전력 모듈의 입력이 내가 상상하는 원하는 것보다 음수가 될 수있을 때까지 "최적화"코드를 더 깨진 본 적이 – user1010005

+4

는 왜 그렇게 많은 표를 받고,'3 6'는 2' – Mysticial

+0

user1010005 @ (이봐, 난이 ... 불평하고 있지 않다) .. 그것은 컴파일러에게 맡기는 간단한 최적화입니다. @ 신비로운 간단한 질문 및 답변은 ​​항상 내 경험에 upvotes의 가장 높은 숫자 (아마 기본적으로 사이트를 방문하는 사람이 첫눈에 대답을 이해하고 있기 때문에 더 upvote 가능성이 높습니다) 유치. 당신이 upvotes 후 경우, 복잡한 SSE 최적화 질문에 대답하는 것은 그것을 얻을 수있는 최악의 방법이다) – Voo

0

다른 사람들이 말했듯이, 범위는 2^n-1이어야하고 심지어 실행 시간에 완료되면 문제가 발생합니다.

최근 아키텍처 (P4 시대 이후의 모든 것)에서 정수 나누기 명령의 대기 시간은 26 ~ 50 정도입니다. 최악의 경우입니다. 비교에서 곱셈은 1-3 사이클이 될 수 있으며 종종 병렬로 수행 될 수 있습니다.

DIV 명령은 EAX의 나머지와 EDX의 나머지를 반환합니다. "나머지"는 자유입니다 (모듈러스는 나머지 임). 당신은 당신이 &를 사용하고자하는 경우 범위, 실행시에 변수 뭔가를 구현하는 경우

, 당신은에 있습니다 범위^N-1이 경우 이렇게 사용하는 경우

가) 확인하여 & 코드 경로 :이 경우 거대한 레이턴시 전위 B)를 첨가 분기 가능한 캐시 미스 등등하지 2^N-1에있어서, DIV를 사용하는 대신에 분기 추가, DIV 명령

를 사용 방정식 (잘못된 캐시 제거와 함께 나쁜 경우에 수백 또는 수천 사이클의 비용이 드는 잠재력)은 DIV를 가장 확실한 선택으로 만듭니다. 또한 부호가있는 데이터 유형과 함께 &을 사용하는 경우 변환이 필요합니다 (혼합 데이터 유형의 경우 &은 없지만 DIV의 경우는 있음). 또한 DIV가 계수에서 분기하는 데에만 사용되고 결과의 나머지가 사용되지 않으면 투기 실행이 효율적으로 수행 될 수 있습니다. 또한 병렬로 명령을 실행할 수있는 다중 파이프 라인을 통해 성능 저하가 더욱 완화됩니다.

실제 코드를 사용하는 경우 많은 캐시가 작업중인 데이터와 곧 작업하거나 작업 한 다른 코드 및 데이터로 가득 차 있다는 것을 기억해야합니다. 실제로 캐시 페이지를 제거하고 분기 예측 오류로 인해 페이지를 기다리는 것을 원하지 않습니다. 대부분의 모듈로, 당신은 i = 7로가는 것이 아닙니다. d = i % 4; 당신은 종종 그 자체가 (예측되고 캐싱 된) 서브 루틴 호출 인 서브 루틴을 호출하는 더 큰 코드를 사용하고 있습니다. 또한 루프 자체에서 분기 예측을 사용하고있을 수도 있습니다. 루프를 가진 중첩 된 분기 예측은 현대 마이크로 프로세서에서 꽤 잘 처리되지만, 예측하려고하는 것을 추가하는 것은 매우 어리 석다.

요약하면 DIV를 사용하면 일반적인 사용 사례에 대해 최신 프로세서에 더 적합합니다. 컴파일러가 캐시 고려 사항 및 다른 것들 때문에 2^n-1을 생성하는 것은 실제로 "최적화"가 아닙니다. 정수 나누기를 미세 조정할 필요가 있고 전체 프로그램이 이에 의존하는 경우 2^n-1로 제수를 하드 코딩하고 비트 단위로 & 논리를 직접 만듭니다.

마지막으로 정수 분할을위한 전용 ALU 유닛은 실제로 데이터 경로가 끝나기 때문에 대기 시간을 6 ~ 8 사이클 정도로 줄이며, 비교적 큰 다이 영역을 차지합니다. 정수 DIV가 어떻게 작동하는지 알 수있을 때 128 비트 너비와 아무도 부동산을 보유하지 못합니다.

관련 문제