부호없는 정수를 가장 가까운 더 작거나 같은 짝수 정수로 반올림하려면 2로 나눈 다음 2를 곱할 수 있습니까?
예 :
f(8)=8
f(9)=8
할 수 있습니까 x = x/2*2;
? 컴파일러가 이러한 표현을 최적화 할 위험이 있습니까?
컴파일러는 프로그램에 부작용을 일으키지 않는 한 원하는 최적화를 할 수 있습니다. 귀하의 경우에는 '2'를 취소 할 수 없으므로식이 홀수에 대해 다른 값을 갖게됩니다.
x / 2 * 2
평가 엄격히 같은 (x / 2) * 2
한 x / 2
경우 정수 연산으로 수행되는 x
일체형이다.
사실 이것은 관용적 반올림 기법입니다.
정수가 부호없는 것으로 지정 했으므로 간단한 마스크로 수행 할 수 있습니다.
x & (~1u)
이는 LSB를 0으로 설정하여보다 크지 않은 즉각적인 짝수를 생성합니다 x
. 경우 즉, x
보다 넓은하지 않는 유형이 있습니다 unsigned int
.
물론 1
다음과 같이 더 넓은 유형과 동일한 유형이되도록 강제 할 수 있습니다 x
.
x & ~((x & 1u) | 1u)
그러나이 시점에서 여러분은이 접근 방식을 난독 화 연습으로보고 밧세바의 대답을 받아 들여야합니다.
물론 표준 라이브러리는 잊어 버렸습니다. 포함하는 경우 stdint.h
(또는 cstdint
, C ++ 코드에서해야 함). 구현에서 세부 사항을 처리하도록 할 수 있습니다.
uintmax_t const lsb = 1;
x & ~lsb;
또는
x & ~UINTMAX_C(1)
C 및 C ++는 일반적으로 최적화에서 "as if"규칙을 사용합니다. 계산 결과는 컴파일러가 코드를 최적화하지 않은 것과 같아야합니다 .
이 경우 9/2*2=8
. 컴파일러는 결과를 얻기 위해 모든 방법을 사용할 수 있습니다. 8. 여기에는 비트 마스크, 비트 시프트 또는 동일한 결과를 생성하는 CPU 특정 해킹이 포함됩니다 (x86에는 포인터를 구분하지 않는다는 사실에 의존하는 몇 가지 트릭이 있습니다. C 및 C ++와 달리 정수).
작성할 수 있으며 x / 2 * 2
컴파일러는 x
부호없는 유형이있는 경우 최하위 비트를 지우는 매우 효율적인 코드를 생성 합니다.
반대로 다음과 같이 작성할 수 있습니다.
x = x & ~1;
또는 가독성이 떨어질 수 있습니다.
x = x & -2;
또는
x = (x >> 1) << 1;
또는 이것도 :
x = x - (x & 1);
또는 supercat이 제안한이 마지막 항목은 모든 정수 유형 및 표현의 양수 값에 대해 작동합니다.
x = (x | 1) ^ 1;
위의 모든 제안은 2의 보수 아키텍처에서 모든 부호없는 정수 유형에 대해 올바르게 작동합니다. 컴파일러가 최적의 코드를 생성할지 여부는 구성 및 구현 품질의 문제입니다.
그러나 x & (~1u)
유형 x
이보다 크면 작동하지 않습니다 unsigned int
. 이것은 직관에 반하는 함정입니다. 당신이 부호없는 정수를 사용하여 주장하는 경우에, 당신은 작성해야 x & ~(uintmax_t)1
조차도 x & ~1ULL
경우 실패 x
보다 더 큰 유형이 있습니다 unsigned long long
. 메이크업 악화 문제에 많은 플랫폼은 지금 형태의보다 큰 정수가 uintmax_t
같은, __uint128_t
.
다음은 약간의 벤치 마크입니다.
typedef unsigned int T;
T test1(T x) {
return x / 2 * 2;
}
T test2(T x) {
return x & ~1;
}
T test3(T x) {
return x & -2;
}
T test4(T x) {
return (x >> 1) << 1;
}
T test5(T x) {
return x - (x & 1);
}
T test6(T x) { // suggested by supercat
return (x | 1) ^ 1;
}
T test7(T x) { // suggested by Mehrdad
return ~(~x | 1);
}
T test1u(T x) {
return x & ~1u;
}
As suggested by Ruslan, testing on Godbolt's Compiler Explorer shows that for all the above alternatives gcc -O1
produces the same exact code for unsigned int
, but changing the type T
to unsigned long long
shows differing code for test1u
.
If your values are of any unsigned type as you say, the easiest is
x & -2;
The wonders of unsigned arithmetic make it that -2
is converted to the type of x
, and has a bit pattern that has all ones, but for the least significant bit which is 0
.
In contrary to some of the other proposed solutions, this should work with any unsigned integer type that is at least as wide as unsigned
. (And you shouldn't do arithmetic with narrower types, anyhow.)
Extra bonus, as remarked by supercat, this only uses conversion of a signed type to an unsigned type. This is well-defined by the standard as being modulo arithmetic. So the result is always UTYPE_MAX-1
for UTYPE
the unsigned type of x
. In particular, it is independent of the sign representation of the platform for signed types.
One option that I'm surprised hasn't been mentioned so far is to use the modulo operator. I would argue this represents your intent at least as well as your original snippet, and perhaps even better.
x = x - x % 2
As others have said, the compiler's optimiser will deal with any reasonable expression equivalently, so worry about what's clearer rather than what you think is fastest. All the bit-tweaking answers are interesting, but you should definitely not use any of them in place of arithmetic operators (assuming the motivation is arithmetic rather than bit tweaking).
just use following:
template<class T>
inline T f(T v)
{
return v & (~static_cast<T>(1));
}
Do not afraid that this is function, compiler should finally optimize this into just v & (~1) with appropriate type of 1.
'developer tip' 카테고리의 다른 글
변경 사항이있는 경우 Laravel Eloquent 업데이트 (0) | 2020.11.07 |
---|---|
쉘에서 화면 지우기 (0) | 2020.11.06 |
Netbeans 작업 영역을 어떻게 새로 고치나요? (0) | 2020.11.06 |
Python에서 가상 메서드를 구현하는 방법은 무엇입니까? (0) | 2020.11.06 |
X509Certificate 생성자 예외 (0) | 2020.11.06 |