2013-08-05 2 views
1

빠른 I/O를 위해이 코드를 발견했습니다.여기서 비트 시프 팅의 요점은 무엇입니까?

#include <cstdio> 

inline void fastRead_int(int &x) { 
    register int c = getchar_unlocked(); 
    x = 0; 
    int neg = 0; 

    for(; ((c<48 || c>57) && c != '-'); c = getchar_unlocked()); 

    if(c=='-') { 
     neg = 1; 
     c = getchar_unlocked(); 
    } 

    for(; c>47 && c<58 ; c = getchar_unlocked()) { 
     x = (x<<1) + (x<<3) + c - 48; 
    } 

    if(neg) 
     x = -x; 
} 

inline void fastRead_string(char *str) 
{ 
    register char c = 0; 
    register int i = 0; 

    while (c < 33) 
     c = getchar_unlocked(); 

    while (c != '\n') { 
     str[i] = c; 
     c = getchar_unlocked(); 
     i = i + 1; 
    } 

    str[i] = '\0'; 
} 

int main() 
{ 

    int n; 
    char s[100]; 

    fastRead_int(n); 
    printf("%d\n", n); 

    fastRead_string(s); 
    printf("%s\n", s); 
    return 0; 
} 

왜 비트 시프트 (X < < 1) + (X < < 3) 있는가? 또한 우리가 음수와 숫자 이외의 문자를 입력하면 어떻게됩니까?

+0

무슨 일이 일어나고 있는지 또는 어떤 기능이 수행 중인지에 대해 알지 못하는 사이에는 비트 연산이 무엇을하는지 알기가 어렵습니다. 어떤 도움이된다면 1 비트 왼쪽 쉬프트는 2를 곱하는 것과 같고 3 비트 왼쪽 쉬프트는 8을 곱하는 것과 같습니다. –

+0

전체 코드를 추가했습니다. 블로그 게시물은 다음과 같습니다. http://digital-madness.in/blog/2013/fast-io-in-c/#comment-2137 기본적으로이 방법은 빠른 I/O를위한 경쟁 프로그래밍에 사용됩니다. – rishiag

+0

'(x << 1) + (x << 3)'은'10'을 곱한 것과 같습니다. 숫자를 10 진수로 표현하면 "left shit"(예 :'12 * 10 = 120')입니다. 'c - 48'은 끝에 새로운 숫자를 추가합니다. – Nbr44

답변

8

왜 비트 시프트 (X < < 1) + (X < < 3) 있는가?

n에 의한 왼쪽 시프트는 2^n과 곱하는 것과 같습니다. 그래서이 식은 10을 곱하는 것과 같습니다 (2^1 + 2^3 = 2 + 8 = 10부터).

코드는 (a) 시프트 및 덧셈이 곱셈보다 훨씬 빠르며 (b) 컴파일러가 10을 곱하는 가장 좋은 방법을 모른다고 믿어서 이렇게 쓰여 있습니다. 이 두 가지 가정은 대부분의 현대 플랫폼에서 잘못되었으므로 더 간단 할뿐만 아니라 더 빨리 읽을 수 있습니다.

네거티브 및 숫자 이외의 문자를 입력하면 어떻게 될까요?

첫 번째 루프는 '-'및 숫자 이외의 항목을 건너 뜁니다. 두 번째 숫자는 숫자가 아닌 숫자를 만나면 (스트림에서 문자를 소비 한 후) 멈 춥니 다. 따라서 입력 스트림에서 찾은 첫 번째 10 진수를 반환하거나없는 경우 0을 반환합니다.예를 들어, 입력이

xxxx123-456xxx-1234xxx 

제 호출 123를 반환을, 상기 제 2 456합니다 (-가 첫 번째 통화가 소비 된 이후에), 제 -1234, 및 상기 호출 0.

+0

모두들 컴파일러보다 똑똑하다고 생각합니다. –

+0

하나의 추가 문자를 사용하면 좋은 점이 있습니다. (하나는 입력을 읽을 때 오버 플로우 여부를 확인하는 것이 중요하다는 것을 추가 할 수 있습니다.) –

+0

그래, 나는 여분의 소비량을 알아 차리지 못했습니다. 그 알고리즘 자체가 여분의 활력으로 제 커피에 도달했습니다. 좋은 캐치. – WhozCraig

1

루틴은 문자 값을 읽고 동일한 작업에서 정수 값으로 변환하는 작업을 빠르게 수행합니다. 변화는 가치의 합계를 돕고 있습니다. 결합 된 교대는 x10과 같습니다.

5

이것은 정말 나쁜 코드입니다. 우선, 48과 57을 사용하는 이유는 이 '0'이고 '9''보다 그리고 귀하의 질문에 관해서는 : 비트 단위 교대는 난독 화에 사용되며, 가능하면 을 감속시킵니다. (x << 1) + (x << 3)이라는 표현식은 이고 숫자는 10 * x입니다. 그냥 덜 읽을 수있어, 및 일부 컴파일러 최적화를 방해 할 수 있습니다. ( 프로세서에서 두 교대와 추가는 곱셈보다 빠르며 컴파일러는 에 대한 변환을 수행합니다. 일반적으로 작성하면 을 알기 때문에 컴파일하는 것이 좋습니다.) 두 번째 질문 : 해당 코드 은 이 숫자 또는 마이너스 기호를 찾을 때까지 모든 문자를 무시한 채 건너 뜁니다. 약간의 오류없이 "abc12"12으로 변환합니다.

실제로, 에러 검사의 총 부재 (및 사용 getchar보다 오히려의 getchar_unlocked)는 빠르게하게된다.

+0

+1 너와 마이크. 게시 된 질문 코드는 디스어셈블러의 출력과 거의 유사하게 보이며 반쯤 이해할 수있는 것으로 손을.니다. – WhozCraig

+0

@WhozCraig 마이크가이 자격이 있다고 생각합니다. 그의 설명은 내 것보다 훨씬 뚜렷하다. * 그리고 * 그는 또한 코드 소비자가 너무 많은 문자를 사용한다는 사실을 발견했다. –

관련 문제