2011-08-15 2 views
72

나는 b로 나누고 싶다면 결과 C와 나머지에 관심이 두렵다. 분 및 초로), 그것에 대해 갈 가장 좋은 방법은 무엇입니까? C++ 가장 좋은 방법은 정수 나누기와 나머지를 얻는 것입니다

그것은

int c = (int)a/b; 
int d = a % b; 

또는

int c = (int)a/b; 
int d = a - b * c; 

또는

double tmp = a/b; 
int c = (int)tmp; 
int d = (int)(0.5+(tmp-c)*b); 

또는

어쩌면 한 번에 하나 모두를 제공하는 마법의 기능이?겠습니까

+4

아래의 모든 대답은 합리적인 것처럼 보입니다. 나는 'double'(마지막 항목)이있는 어떤 mucking도 나에게 나쁜 생각을하는 것처럼 보인다고 덧붙이고 싶습니다. 줄을 서지 않는 숫자로 끝나고, 성능 및 실행 가능한 크기로 비용을 부담 할 수 있습니다 (특정 임베디드 시스템에서 항상 문제가되었습니다). – nhed

+2

세 번째는 BAD 옵션입니다. tmp = 54.999999999999943157 일 경우 어떻게해야합니까? 이것은 오래된 스타일의 캐스팅이 결코 영리한 일이 아니라고 말했습니다. – jimifiki

답변

71

x86에서 나머지는 부분 자체의 부산물이므로 모든 반 기울임 컴파일러는이를 사용하고 다시 div을 수행 할 수 없습니다. 아마도 다른 아키텍처에서도 마찬가지입니다.

명령 : DIV SRC

참고 : 부호 분할. 누산기 (AX)를 "src"로 나눕니다. 이 바이트 값이면 결과는 AL 이고 나머지 값은 A이됩니다. 제수가 이 단어 값이면 DX : AX를 "src"로 나눈 결과가 이고 축이 이고 나머지가 DX에 저장됩니다.

int c = (int)a/b; 
int d = a % b; /* Likely uses the result of the division. */ 
+6

나는 초등 학교에서 많은 일을하고 있다고 생각한다. 진짜 질문은 : 우리의 컴파일러가 이것을 활용할만큼 똑똑한가? –

+0

동의 -하지만 b가 2의 거듭 제곱이면 비트 시프트를 사용할 수 있습니다. –

+1

@jdv : 나는 놀라지 않을 것입니다. 그것은 매우 간단한 최적화입니다. –

57

std::div는 결과와 나머지 모두 구조를 반환합니다.

+4

이것이 실제로 현대 컴파일러에서 옵션 1보다 효율적인지 궁금합니다. –

+2

니스, 나는 몰랐다. 더 빠릅니까? –

+0

니스. 하나가 오래도록 구현 된 경우 어딘가에 있는지 알고 싶습니까? – Cookie

-3

나머지를 얻기 위해 모듈을 사용할 수 있습니다. @ cnicutar의 대답은 더 깨끗하고/더 직접적으로 보입니다.

+1

예, 원래 포스터는 모듈러스 연산자를 사용했습니다. 문제는 효율적으로 만드는 방법입니다. –

3

그 밖의 모든 것이 평등하다면 가장 좋은 해결책은 의도를 명확하게 표현하는 것입니다. 따라서 :

int totalSeconds = 453; 
int minutes = totalSeconds/60; 
int remainingSeconds = totalSeconds % 60; 

은 아마도 당신이 제시 한 세 가지 옵션 중에서 가장 좋습니다. 그러나 다른 답변에서 언급했듯이 div 방법은 한 번에 두 값을 모두 계산합니다.

+3

명백하게 질문은 속도에 대해 묻고 있습니다 ... – Pacerier

21

적어도 x86에서 g ++ 4.6.1은 IDIVL을 사용하고 그 단일 명령에서 둘 모두를 가져옵니다.

C++ 코드 :

void foo(int a, int b, int* c, int* d) 
{ 
    *c = a/b; 
    *d = a % b; 
} 

코드 86 :

__Z3fooiiPiS_: 
LFB4: 
    movq %rdx, %r8 
    movl %edi, %edx 
    movl %edi, %eax 
    sarl $31, %edx 
    idivl %esi 
    movl %eax, (%r8) 
    movl %edx, (%rcx) 
    ret 
+0

주문이 중요합니까? 예를 들어,'/ ='를 반복 할 경우, 먼저 나누기를 유지하기 위해 임시 변수를 사용해야 할 수도 있습니다. – Annan

6

샘플 코드 테스트 DIV()와 함께 분할 & 개조. gcc -O3으로 컴파일했는데 doNothing에 대한 호출을 추가하여 컴파일러가 모든 것을 최적화하지 못하게했습니다 (출력은 division + mod 솔루션에 대해 0이됩니다).

#include <stdio.h> 
#include <sys/time.h> 
#include <stdlib.h> 

extern doNothing(int,int); // Empty function in another compilation unit 

int main() { 
    int i; 
    struct timeval timeval; 
    struct timeval timeval2; 
    div_t result; 
    gettimeofday(&timeval,NULL); 
    for (i = 0; i < 1000; ++i) { 
     result = div(i,3); 
     doNothing(result.quot,result.rem); 
    } 
    gettimeofday(&timeval2,NULL); 
    printf("%d",timeval2.tv_usec - timeval.tv_usec); 
} 

출력 : 150

#include <stdio.h> 
#include <sys/time.h> 
#include <stdlib.h> 

extern doNothing(int,int); // Empty function in another compilation unit 

int main() { 
    int i; 
    struct timeval timeval; 
    struct timeval timeval2; 
    int dividend; 
    int rem; 
    gettimeofday(&timeval,NULL); 
    for (i = 0; i < 1000; ++i) { 
     dividend = i/3; 
     rem = i % 3; 
     doNothing(dividend,rem); 
    } 
    gettimeofday(&timeval2,NULL); 
    printf("%d",timeval2.tv_usec - timeval.tv_usec); 
} 

출력 :

소금의 입자로를 타고 25

3

당신은 믿을 수 g ++ A의 64 개 비트 정수와 여기에 4.6.3 32 비트 인텔 플랫폼. a/b는 divdi3에 대한 호출에 의해 계산되고 % b는 moddi3에 대한 호출에 의해 계산됩니다. 이 호출을 사용하여 a/b와 a-b * (a/b)를 계산하는 예제를 생각해 낼 수도 있습니다. 그래서 저는 c = a/b와 a-b * c를 사용합니다.

div 메서드는 div 구조를 계산하는 함수를 호출하지만 정수형 (즉, 64 비트 intel/amd 플랫폼의 경우 64 비트 정수)에 대한 하드웨어 지원이있는 플랫폼에서는 함수 호출이 비효율적으로 보입니다.