- 비트 연산을 무엇에 사용 했습니까?
- 왜 그렇게 편리할까요?
- 누군가 아주 간단한 튜토리얼을 추천 해 주시겠습니까?
답변
모든 사람이 플래그 사용 사례에 푹 빠져있는 것처럼 보이지만, 이것이 비트 연산자의 유일한 응용 프로그램은 아닙니다 (가장 일반적이지만). 또한 C #은 다른 기술이 거의 사용되지 않을만큼 충분히 높은 수준의 언어이지만 여전히 알아 두어야 할 가치가 있습니다. 내가 생각할 수있는 것은 다음과 같습니다.
<<
그리고 >>
당신이 정말로 모든 마이크로를 통해 초조해하는 경우 사업자는 빠르게 증식 물론 2의 힘으로, 닷넷 JIT 최적화는 아마 당신을 당신 (그리고뿐만 아니라 다른 언어의 어떤 점잖은 컴파일러)이 작업을 수행하지만, 할 수 있습니다 확실히하기 위해 이것을 쓸 수도 있습니다.
이러한 연산자의 또 다른 일반적인 용도는 두 개의 16 비트 정수를 하나의 32 비트 정수로 채우는 것입니다. 처럼:
int Result = (shortIntA << 16 ) | shortIntB;
이것은 종종 레거시 이유로이 트릭을 사용하는 Win32 함수와 직접 인터페이스하는 경우에 일반적입니다.
물론 이러한 연산자는 숙제 질문에 대한 답변을 제공 할 때와 같이 경험이없는 사용자를 혼동하고 싶을 때 유용합니다. 🙂
그것은 훨씬 더 나은 가독성을 가지고 있기 때문에 실제 코드에서 당신은 훨씬 더 떨어져 대신 곱셈을 사용하여 수 있습니다 불구하고 JIT는 그것을 최적화 shl
및 shr
지침 어쨌든 때문에 성능 저하가 없다.
^
연산자 (XOR)를 다루는 몇 가지 흥미로운 트릭이 있습니다. 이것은 실제로 다음과 같은 속성으로 인해 매우 강력한 연산자입니다.
A^B == B^A
A^B^A == B
- 당신이 알고 있다면
A^B
그것은 무엇을 얘기하는 것은 불가능A
하고B
,하지만 당신은 그들 중 하나를 알고 있다면, 당신은 다른 사람을 계산할 수 있습니다. - 연산자는 곱셈 / 나눗셈 / 더하기 / 빼기와 같은 오버플로를 겪지 않습니다.
이 연산자를 사용하여 본 몇 가지 트릭 :
중간 변수없이 두 개의 정수 변수 교체 :
A = A^B // A is now XOR of A and B
B = A^B // B is now the original A
A = A^B // A is now the original B
항목 당 하나의 추가 변수 만있는 이중 연결 목록입니다. 이것은 C #에서 거의 사용되지 않지만 모든 바이트가 중요한 임베디드 시스템의 저수준 프로그래밍에 유용 할 수 있습니다.
아이디어는 첫 번째 항목에 대한 포인터를 추적하는 것입니다. 마지막 항목에 대한 포인터; 추적하는 모든 항목에 대해 pointer_to_previous ^ pointer_to_next
. 이렇게하면 양쪽 끝에서 목록을 순회 할 수 있지만 오버 헤드는 기존 연결 목록의 절반에 불과합니다. 순회를위한 C ++ 코드는 다음과 같습니다.
ItemStruct *CurrentItem = FirstItem, *PreviousItem=NULL;
while ( CurrentItem != NULL )
{
// Work with CurrentItem->Data
ItemStruct *NextItem = CurrentItem->XorPointers ^ PreviousItem;
PreviousItem = CurrentItem;
CurrentItem = NextItem;
}
끝에서 횡단하려면 첫 번째 줄을에서 FirstItem
로 변경하면 됩니다 LastItem
. 그것은 바로 거기에 또 다른 메모리 절약입니다.
^
C #에서 정기적으로 연산자를 사용하는 또 다른 곳 은 복합 유형 인 내 유형에 대한 HashCode를 계산해야 할 때입니다. 처럼:
class Person
{
string FirstName;
string LastName;
int Age;
public int override GetHashCode()
{
return (FirstName == null ? 0 : FirstName.GetHashCode()) ^
(LastName == null ? 0 : LastName.GetHashCode()) ^
Age.GetHashCode();
}
}
답변
내 응용 프로그램의 보안을 위해 비트 연산자를 사용합니다. Enum 안에 다양한 레벨을 저장하겠습니다.
[Flags]
public enum SecurityLevel
{
User = 1, // 0001
SuperUser = 2, // 0010
QuestionAdmin = 4, // 0100
AnswerAdmin = 8 // 1000
}
그런 다음 사용자에게 수준을 할당합니다.
// Set User Permissions to 1010
//
// 0010
// | 1000
// ----
// 1010
User.Permissions = SecurityLevel.SuperUser | SecurityLevel.AnswerAdmin;
그런 다음 수행중인 작업의 권한을 확인합니다.
// Check if the user has the required permission group
//
// 1010
// & 1000
// ----
// 1000
if( (User.Permissions & SecurityLevel.AnswerAdmin) == SecurityLevel.AnswerAdmin )
{
// Allowed
}
답변
나는 당신이 생각하는 스도쿠를 해결하는 것이 얼마나 실용적인지 모르겠지만 그것이 있다고 가정합시다.
보드를 보여주고 퍼즐을 직접 풀 수 있지만 동작이 합법적인지 확인하는 스도쿠 해결사 또는 단순한 프로그램을 작성하고 싶다고 상상해보십시오.
보드 자체는 아마도 다음과 같은 2 차원 배열로 표현 될 것입니다.
uint [, ] theBoard = new uint[9, 9];
값 0
은 셀이 여전히 비어 있고 [1u, 9u] 범위의 값이 보드의 실제 값임을 의미합니다.
이제 어떤 움직임이 합법적인지 확인하고 싶다고 상상해보십시오. 분명히 몇 개의 루프로 할 수 있지만 비트 마스크를 사용하면 작업을 훨씬 빠르게 할 수 있습니다. 규칙을 준수하는 단순한 프로그램에서는 중요하지 않지만 솔버에서는 가능합니다.
각 행, 각 열 a 및 각 3×3 상자에 이미 삽입 된 숫자에 대한 정보를 저장하는 비트 마스크 배열을 유지할 수 있습니다.
uint [] maskForNumbersSetInRow = new uint[9];
uint [] maskForNumbersSetInCol = new uint[9];
uint [, ] maskForNumbersSetInBox = new uint[3, 3];
숫자 세트에 해당하는 1 비트를 사용하여 숫자에서 비트 패턴으로의 매핑은 매우 간단합니다.
1 -> 00000000 00000000 00000000 00000001
2 -> 00000000 00000000 00000000 00000010
3 -> 00000000 00000000 00000000 00000100
...
9 -> 00000000 00000000 00000001 00000000
C #에서는 다음과 같이 비트 패턴을 계산할 수 있습니다 ( value
is an uint
).
uint bitpattern = 1u << (int)(value - 1u);
위의 줄 1u
에서 비트 패턴에 해당하는 것은 00000000 00000000 00000000 00000001
왼쪽으로 이동합니다 value - 1
. 예를 들어 value == 5
다음과 같은 경우
00000000 00000000 00000000 00010000
처음에 각 행, 열 및 상자의 마스크는 0
입니다. 보드에 숫자를 입력 할 때마다 마스크를 업데이트하므로 새 값에 해당하는 비트가 설정됩니다.
행 3에 값 5를 삽입한다고 가정합니다 (행과 열은 0부터 번호가 매겨 짐). 행 3의 마스크는에 저장됩니다 maskForNumbersSetInRow[3]
. 삽입하기 전에 이미 {1, 2, 4, 7, 9}
행 3에 숫자가 있다고 가정 해 보겠습니다 . 마스크의 비트 패턴은 maskForNumbersSetInRow[3]
다음과 같습니다.
00000000 00000000 00000001 01001011
bits above correspond to:9 7 4 21
목표는이 마스크의 값 5에 해당하는 비트를 설정하는 것입니다. 비트 또는 연산자 ( |
)를 사용하여 수행 할 수 있습니다 . 먼저 값 5에 해당하는 비트 패턴을 만듭니다.
uint bitpattern = 1u << 4; // 1u << (int)(value - 1u)
그런 다음을 사용 operator |
하여 마스크에 비트를 설정합니다.maskForNumbersSetInRow[3]
maskForNumbersSetInRow[3] = maskForNumbersSetInRow[3] | bitpattern;
또는 더 짧은 형식 사용
maskForNumbersSetInRow[3] |= bitpattern;
00000000 00000000 00000001 01001011
|
00000000 00000000 00000000 00010000
=
00000000 00000000 00000001 01011011
이제 마스크는 {1, 2, 4, 5, 7, 9}
이 행 (3 행)에 값 이 있음을 나타냅니다 .
확인하고자하는 경우 행에 어떤 값이 operator &
있으면 해당 비트가 마스크에 설정되어 있는지 확인하는 데 사용할 수 있습니다 . 마스크에 적용된 해당 연산자의 결과와 해당 값에 해당하는 비트 패턴이 0이 아니면 값이 이미 행에있는 것입니다. 결과가 0이면 값은 행에 없습니다.
예를 들어 값 3이 행에 있는지 확인하려면 다음과 같이 할 수 있습니다.
uint bitpattern = 1u << 2; // 1u << (int)(value - 1u)
bool value3IsInRow = ((maskForNumbersSetInRow[3] & bitpattern) != 0);
00000000 00000000 00000001 01001011 // the mask
|
00000000 00000000 00000000 00000100 // bitpattern for the value 3
=
00000000 00000000 00000000 00000000 // the result is 0. value 3 is not in the row.
다음은 보드에 새 값을 설정하고 적절한 비트 마스크를 최신 상태로 유지하고 이동이 합법적인지 확인하는 방법입니다.
public void insertNewValue(int row, int col, uint value)
{
if(!isMoveLegal(row, col, value))
throw ...
theBoard[row, col] = value;
uint bitpattern = 1u << (int)(value - 1u);
maskForNumbersSetInRow[row] |= bitpattern;
maskForNumbersSetInCol[col] |= bitpattern;
int boxRowNumber = row / 3;
int boxColNumber = col / 3;
maskForNumbersSetInBox[boxRowNumber, boxColNumber] |= bitpattern;
}
마스크가 있으면 다음과 같이 이동이 합법적인지 확인할 수 있습니다.
public bool isMoveLegal(int row, int col, uint value)
{
uint bitpattern = 1u << (int)(value - 1u);
int boxRowNumber = row / 3;
int boxColNumber = col / 3;
uint combinedMask = maskForNumbersSetInRow[row] | maskForNumbersSetInCol[col]
| maskForNumbersSetInBox[boxRowNumber, boxColNumber];
return ((theBoard[row, col] == 0) && ((combinedMask & bitpattern) == 0u);
}
답변
코드는 C로되어 있지만 C #에 쉽게 적용 할 수 있습니다.
답변
하드웨어와 통신해야하는 경우 어느 시점에서 비트 트위들 링을 사용해야합니다.
픽셀 값의 RGB 값 추출.
너무 많은 것들
답변
- 하나의 제한된 크기 변수를 통해 함수에 많은 인수를 전달하는 데 사용할 수 있습니다.
- 장점은 낮은 메모리 오버 헤드 또는 낮은 메모리 비용입니다. 따라서 성능이 향상됩니다.
- 나는 그 자리에서 튜토리얼을 쓸 수 없지만 거기에 있다고 확신합니다.
답변
그것들은 다른 응용 프로그램의 전체 부하에 사용할 수 있습니다. 여기에 비트 연산을 사용하는 이전에 여기에 게시 한 질문이 있습니다.
다른 예를 보려면 플래그가 지정된 열거를 살펴보십시오.
내 예에서는 비트 연산을 사용하여 이진수의 범위를 -128 … 127에서 0..255로 변경했습니다 (표현식을 부호 있음에서 부호 없음으로 변경).
여기에 MSN 기사->
http://msdn.microsoft.com/en-us/library/6a71f45d%28VS.71%29.aspx
유용합니다.
그리고이 링크 :
매우 기술적이며 모든 것을 다루고 있습니다.
HTH