정수를 2로 나눌 때 어떤 옵션을 사용하는 것이 더 좋을까요?
다음 중 정수를 2로 나누는 가장 좋은 방법은 무엇이고 그 이유는 무엇입니까?
기술 1:
x = x >> 1;
기술 2:
x = x / 2;
여기서x
는 정수입니다.
실행하려는 작업에 가장 적합한 작업을 사용하십시오.
- 숫자를 일련의 비트로 취급하는 경우는, 비트 시프트를 사용합니다.
- 수치로 취급하는 경우는, 나눗셈을 사용합니다.
이 두 가지가 완전히 동일하지는 않다는 점에 유의하십시오.음의 정수에 대해 서로 다른 결과를 얻을 수 있습니다.예를 들어 다음과 같습니다.
-5 / 2 = -2
-5 >> 1 = -3
첫 번째는 나누는 것처럼 보이나요?아니요. 분할하려면x / 2
컴파일러는 가능하면 비트 시프트를 사용하도록 최적화할 수 있습니다(강도의 저감이라고 합니다).이것에 의해, 독자적으로 실시하면, 마이크로 최적화는 불필요하게 됩니다.
덧붙이자면, 사용하는 것을 선호하는 이유는 매우 많습니다.x = x / 2;
다음은 몇 가지 예입니다.
그것은 당신의 의도를 더 명확하게 표현한다(레지스터 비트 같은 것을 약간 만지작거리고 있지 않은 경우).
컴파일러는 어쨌든 이것을 시프트 조작으로 줄일 것이다.
컴파일러가 그것을 줄이지 않고 시프트보다 느린 동작을 선택했다고 해도, 이것이 프로그램의 퍼포먼스에 측정 가능한 방법으로 영향을 줄 가능성은 매우 작다(그리고 그것이 측정 가능한 영향을 준다면, 시프트를 사용할 실제 이유가 있다).
나눗셈이 더 큰 식에 포함될 경우 나눗셈 연산자를 사용하면 우선 순위를 얻을 수 있습니다.
x = x / 2 + 5; x = x >> 1 + 5; // not the same as above
서명된 산술은 위에서 언급한 우선순위 문제보다 더 복잡한 문제를 일으킬 수 있다
다시 말씀드리지만 컴파일러는 이미 이 작업을 수행합니다.실제로 2의 거듭제곱뿐만 아니라 모든 종류의 숫자에 대해 정수 나눗셈을 일련의 이동, 덧셈 및 곱셈으로 변환합니다.이에 대한 자세한 내용은 이 질문을 참조하십시오.
간단히 말해, 실제로 곱셈이나 나누기를 의도할 때 교대조를 코딩하여 아무것도 사지 않는 것입니다. 단, 버그가 발생할 가능성이 높아집니다.컴파일러가 적절할 때 이러한 작업을 최적화할 수 있을 만큼 똑똑하지 못한 것은 평생의 일입니다.
divide만 사용하세요./
보다 명확하다고 가정합니다.그에 따라 컴파일러가 최적화됩니다.
정수를 2로 나누는 가장 좋은 선택지와 이유는 무엇입니까?
그게 무슨 뜻이냐에 따라 다르죠
동료들이 당신을 싫어하거나 코드를 읽기 어렵게 만들고 싶다면 첫 번째 옵션을 선택하겠어요.
숫자를 2로 나누려면 두 번째 숫자로 하세요.
이 두 가지는 동일하지 않습니다.숫자가 음수이거나 큰 식 안에 있는 경우 동작은 동일하지 않습니다.비트 시프트는 비트 시프트보다 우선도가 낮습니다.+
또는-
, division의 우선순위가 높아집니다.
그 의도가 무엇인지 표현하기 위해 코드를 작성해야 합니다.퍼포먼스가 걱정되는 경우라면 걱정하지 마세요.옵티마이저는 이러한 종류의 미세 최적화를 훌륭하게 수행할 수 있습니다.
당신이 찬성해야 할 다른 답변에 동의합니다.x / 2
왜냐하면 그 의도가 더 명확하고 컴파일러가 당신을 위해 최적화해야 하기 때문입니다.
단, 다른 이유로는x / 2
에 걸쳐서x >> 1
의 행동이>>
구현에 의존합니다.x
서명된int
음성이에요.
섹션 6.5.7에서 ISO C99 표준의 항목 5:
의 결과
E1 >> E2
이E1
오른쪽 방향의E2
비트 위치한다면E1
부호 없는 타입을 가지거나E1
부호 있는 유형과 음이 아닌 값을 가지며, 결과의 값은 의 몫의 정수 부분입니다.E1
/ 2E2
. 만약E1
는 부호 있는 유형과 음의 값을 가지며, 결과 값은 구현 정의됩니다.
Knuth는 말했다:
섣부른 최적화는 모든 악의 근원이다.
그래서 나는 그것을 사용하는 것을 추천한다.x /= 2;
이렇게 하면 코드를 쉽게 이해할 수 있을 뿐만 아니라 프로세서에 큰 차이는 없다고 생각합니다.
대회를 프로그래밍할 목적으로 말씀드리는 겁니다.일반적으로 2로 나누기가 여러 번 일어나고 입력이 양수 또는 음수인 것으로 알려진 매우 큰 입력이 있습니다.
x>1이 x/2보다 낫다.ideone.com에서 10^10 나눗셈 2개 이상의 연산이 이루어지는 프로그램을 실행하여 확인하였습니다.x/2는 5.5초 가까이 소요된 반면 x>1은 같은 프로그램에서 거의 2.6초 소요되었습니다.
컴파일러의 출력을 참조해 주세요.x86-64에서 이 테스트를 실행했습니다.
gcc (GCC) 4.2.1 20070719 [FreeB]SD]
godbolt의 온라인 컴파일러 출력도 참조해 주세요.
컴파일러가 사용하고 있는 것은sarl
(산술 오른쪽 이동) 명령으로 두 표현 사이의 유사성을 인식합니다.나눗셈을 사용하는 경우 컴파일러도 음수에 맞게 조정해야 합니다.이를 위해 부호 비트를 최하위 비트로 이동하고 그 값을 결과에 추가합니다.이렇게 하면 나눗셈이 수행하는 작업에 비해 음수 이동 시 하나씩 문제가 해결됩니다.
나눗셈 케이스는 2개의 시프트를 실시하지만 명시적인 시프트 케이스는 1개의 시프트만을 실시하기 때문에, 여기에서는 다른 답변에 의해 측정된 퍼포먼스 차이 중 일부를 설명할 수 있습니다.
어셈블리 출력이 있는 C 코드:
나눗셈의 경우 입력은 다음과 같습니다.
int div2signed(int a) {
return a / 2;
}
그리고 이것은 다음과 같이 정리된다.
movl %edi, %eax
shrl $31, %eax
addl %edi, %eax
sarl %eax
ret
교대근무를 위해서도 마찬가지로
int shr2signed(int a) {
return a >> 1;
}
출력:
sarl %edi
movl %edi, %eax
ret
x / 2
더 선명하고x >> 1
(마이크로 벤치마크에 따르면 Java JVM의 경우 약 30% 더 빠릅니다)다른 사람들이 지적한 바와 같이 음수의 경우 반올림이 약간 다르므로 음수를 처리하려면 이 점을 고려해야 합니다.일부 컴파일러는 자동으로 변환됩니다.x / 2
로.x >> 1
만약 그들이 그 숫자가 음수가 될 수 없다는 것을 안다면(내가 이것을 확인할 수 없다고 생각해도).
심지어.x / 2
(저속) 분할 CPU 명령을 사용할 수 없는 경우가 있습니다.이것은 일부 숏컷이 가능하지만, 아직 CPU 명령보다 느리기 때문입니다.x >> 1
.
(이것은 C/C++ 질문입니다.다른 프로그래밍 언어에는 연산자가 더 많습니다.Java의 경우 부호 없는 오른쪽 시프트도 있습니다.x >>> 1
이 역시 다릅니다.두 값의 평균(평균) 값을 정확하게 계산할 수 있습니다.(a + b) >>> 1
매우 큰 값이라도 평균값을 반환한다.a
그리고.b
이는 예를 들어 배열 인덱스가 매우 커질 수 있는 바이너리 검색에서 필요합니다.바이너리 검색의 많은 버전에는 버그가 있었습니다.왜냐하면 그들은(a + b) / 2
평균을 계산합니다.이건 제대로 작동하지 않아요.올바른 해결방법은(a + b) >>> 1
대신).
메모 추가 -
x *= 0.5는 일부 VM 기반 언어(특히 변수가 0으로 나누어져 있는지 확인할 필요가 없으므로 작업 스크립트)에서 더 빠릅니다.
사용하다x = x / 2;
또는x /= 2;
장래에 새로운 프로그래머가 작업할 가능성이 있기 때문입니다.그래서 그가 코드 라인에서 무슨 일이 일어나고 있는지 알아내는 것이 더 쉬울 것이다.누구나 이러한 최적화를 인식하지 못할 수 있습니다.
고려해야 할 사항이 몇 가지 있습니다.
비트 시프트는 비트 시프트에 특별한 연산이 필요하지 않기 때문에 더 빨라야 하지만 지적했듯이 음수에 문제가 있을 수 있습니다.만약 당신이 확실히 양수를 가지고 있고 속도를 찾고 있다면, 나는 bitsshift를 추천한다.
나눗셈 연산자는 사람이 읽기 매우 쉽다.따라서 코드를 읽기 쉽게 하려면 이 방법을 사용할 수 있습니다.컴파일러 최적화 분야는 크게 발전했기 때문에 코드를 쉽게 읽고 이해할 수 있도록 하는 것이 좋습니다.
- 기본 하드웨어에 따라 작업 속도가 다를 수 있습니다.암달의 법칙은 일반적인 경우를 빠르게 만드는 것이다.따라서 다른 작업보다 더 빠르게 다른 작업을 수행할 수 있는 하드웨어가 있을 수 있습니다.예를 들어 0.5를 곱하는 것이 2로 나누는 것보다 더 빠를 수 있습니다(정수 나눗셈을 적용하려면 곱셈의 바닥을 사용해야 할 수도 있습니다).
순수 성능을 원하는 경우 수백만 번 연산을 수행할 수 있는 테스트를 만들 것을 권장합니다.OS/하드웨어/컴파일러/코드에 통계적으로 가장 적합한 실행을 여러 번 샘플 크기(샘플 크기)로 확인합니다.
CPU에 관한 한 비트 시프트 동작은 분할 동작보다 빠릅니다.다만, 컴파일러는 이것을 알고 있기 때문에, 가능한 한 적절히 최적화할 수 있기 때문에, 가장 적절한 방법으로 코드를 코드화할 수 있어 코드가 효율적으로 동작하고 있는 것을 알 수 있어 안심할 수 있습니다.하지만 기억해라unsigned int
(경우에 따라서는) 보다 최적화할 수 있다int
앞서 지적한 이유로서명된 산술이 필요하지 않은 경우 기호 비트를 포함하지 마십시오.
x = x / 2; 이 사용하기에 적합한 코드입니까?다만, 조작은, 출력의 작성 방법에 관한 독자적인 프로그램에 의해서 다릅니다.
당신의 의도를 명확히 하세요...예를 들어, 분할하려면 x / 2를 사용하고, 컴파일러가 연산자(또는 다른 것)를 이동시키도록 최적화합니다.
오늘날의 프로세서는 이러한 최적화가 프로그램의 성능에 영향을 미치지 않도록 합니다.
이에 대한 답은 작업 환경에 따라 달라집니다.
- 8비트 마이크로컨트롤러 또는 멀티플리케이션을 하드웨어로 지원하지 않는 경우 비트 시프트가 예상되며 컴파일러는 거의 확실하게 동작합니다.
x /= 2
안으로x >>= 1
나눗셈 기호의 존재는 나눗셈을 하기 위해 시프트를 사용하는 것보다 그 환경에서 더 많은 눈살을 찌푸리게 할 것이다. - 퍼포먼스가 중요한 환경이나 코드의 일부에서 작업하고 있는 경우, 또는 컴파일러 최적화가 꺼진 상태에서 코드를 컴파일 할 수 있는 경우,
x >>= 1
그 이유를 설명하는 코멘트와 함께 아마도 목적을 명확히 하기 위해서만 최선일 것이다. - 위의 조건 중 하나에 해당하지 않는 경우 단순히 다음을 사용하여 코드를 보다 쉽게 읽을 수 있도록 합니다.
x /= 2
시프트가 더 효율적인 산스 컴파일러 최적화라는 것을 불필요하게 증명하기보다는 당신의 시프트 작업을 10초간 더블테이크 하는 다음 프로그래머를 구하는 것이 좋습니다.
이 모든 것은 부호 없는 정수를 가정합니다.간단한 교대 근무는 서명에 적합하지 않을 수 있습니다.또한, DanielH는 DanielH를 사용하는 것에 대해 좋은 점을 제기합니다.x *= 0.5
ActionScript와 같은 특정 언어용입니다.
mod 2, = 1. c.의 구문을 모르지만 이 방법이 가장 빠를 수 있습니다.
일반적으로 오른쪽 시프트 분할:
q = i >> n; is the same as: q = i / 2**n;
이것은 때때로 명확성을 희생하면서 프로그램의 속도를 높이기 위해 사용됩니다.당신이 그걸 꼭 해야하는건 아니라고 생각해요.컴파일러는 자동적으로 스피드 업을 실행할 수 있을 만큼 스마트합니다.즉, 시프트를 도입하는 것은 명확성을 희생하는 것이 아닙니다.
Practical C++ Programming의 이 페이지를 참조해 주세요.
다음 번 읽는 사람을 위해 코드를 작성하는 경우 "x/2"의 선명도를 선택하십시오.
하지만, 속도가 목표라면, 두 가지 방법으로 시도하고 결과를 측정해 보세요.몇 달 전에 저는 비트맵 컨볼루션 루틴을 작성했습니다.정수의 배열을 밟아 각 요소를 2로 나누는 것입니다.최적화를 위해 x/2를 x>1로 대체하는 구태의연한 수법을 구사했습니다.
실제로 양쪽의 타이밍을 측정했을 때 놀랍게도 x/2가 x>1보다 빨랐습니다.
이것은 Microsoft VS2008 C++ 를 사용해 디폴트의 최적화를 유효하게 하고 있습니다.
퍼포먼스 면에서는요.CPU의 시프트 조작은, 분할 op-code보다 큰폭으로 고속입니다.따라서 2로 나누거나 2로 곱하는 것은 모두 교대조 운영의 이점을 얻을 수 있습니다.
모양과 느낌에 대해서요.엔지니어로서 우리는 언제부터 아름다운 여성도 사용하지 않는 화장품에 애착을 갖게 되었을까! :)
X/Y는 올바른 연산자이고 ">>" 시프트 연산자..2를 정수로 나누려면 (/) 배당 연산자를 사용할 수 있습니다.시프트 연산자는 비트를 이동하는 데 사용됩니다.
x=x/2; x/=2; 이렇게 사용할 수 있습니다.
x>1은 x/2보다 빠르지만 음의 값을 처리할 때 >>를 적절하게 사용하는 것은 조금 복잡합니다.다음과 같은 것이 필요합니다.
// Extension Method
public static class Global {
public static int ShiftDivBy2(this int x) {
return (x < 0 ? x + 1 : x) >> 1;
}
}
언급URL : https://stackoverflow.com/questions/10681375/which-is-better-option-to-use-for-dividing-an-integer-number-by-2
'source' 카테고리의 다른 글
PHP: 현재 날짜의 월을 가져오는 날짜 함수 (0) | 2022.09.16 |
---|---|
는 해시의 또 다른 배열(perl)에서 팔지 않는 해시도 하나의 배열에 있는 요소 확인. (0) | 2022.09.16 |
MariaDB JDBC 클라이언트 로깅이 작동하지 않음 (0) | 2022.09.16 |
JavaScript에서 backtick 문자(') 사용 (0) | 2022.09.16 |
각도 2 호버 이벤트 (0) | 2022.09.16 |