여러 부울 상태를 하나의 숫자로 저장 / 포장하는 이름은 무엇입니까?


55

두 개의 숫자를 사용하여 하나의 숫자 변수를 사용하여 여러 부울 / 이진 상태를 저장하는 일종의 간단한 압축 방식이며 모든 배가 숫자는 1 + 이전 숫자의 합계 + 1입니다.

나는 그것이 오래되고 잘 알려진 기술이어야한다고 확신합니다. 제대로 참조하기 위해 무엇을 부르는지 알고 싶습니다. 나는 그것을 설명하기 위해 생각할 수있는 모든 방법으로 여러 번 검색했지만 기사 작성자가 직접 알아 냈고 무엇을 호출 해야할지 모르는 블로그 기사 외에는 아무것도 발견하지 못했습니다 ( 예 1 , 예 2 ).

예를 들어, 다음은 개념을 설명하기위한 매우 간단한 구현입니다.

packStatesIntoNumber () {
  let num = 0
  if (this.stateA) num += 1
  if (this.stateB) num += 2
  if (this.stateC) num += 4
  if (this.stateD) num += 8
  if (this.stateE) num += 16
  if (this.stateF) num += 32
  return num
}

unpackStatesFromNumber (num) {
  assert(num < 64)
  this.stateF = num >= 32; if (this.stateF) num -= 32
  this.stateE = num >= 16; if (this.stateE) num -= 16
  this.stateD = num >= 8; if (this.stateD) num -= 8
  this.stateC = num >= 4; if (this.stateC) num -= 4
  this.stateB = num >= 2; if (this.stateB) num -= 2
  this.stateA = num >= 1; if (this.stateA) num -= 1
}

비트 연산자, 기본 2 숫자 구문 분석, 열거 형을 사용할 수도 있습니다. 그것을 구현하는 더 효율적인 방법이 많이 있습니다. 접근 방식의 이름에 더 일반적으로 관심이 있습니다.


8
C #에는가 있으며 속성을 enums가질 수 있습니다 Flags. 코드를 훨씬 간단하게 만들 수 있습니다.
Bernhard Hiller

12
이것을 "시뮬레이션 비트 필드"라고 부릅니다. 공간 효율성이 압도적으로 중요하지 않으면 거의 항상 나쁜 생각입니다.
Kilian Foth

7
@KilianFoth A bool는 일반적으로 내부적으로 32 비트 정수로 저장됩니다. 따라서 패킹은 32 배의 차이를 만들 수 있습니다. 정말 많은 부분입니다. 우리 프로그래머들은 항상 우리 자원의 절반을 버릴 준비가되어 있지만, 일반적으로 97 %를 버리는 것을 꺼려합니다. 이러한 낭비 요인으로 인해 중요한 사용 사례를 실행할 수있는 것과 메모리 부족이 쉽게 달라질 수 있습니다.
cmaster

3
역사적으로 비트 마스크는 일반적으로 값을 선언, 설정 및 검색하는 데 사용됩니다. 교대를 사용하는 것은 이상하고 실제로 가장 좋은 접근법은 아닙니다.
JimmyJames

3
@cmaster bool이 저장되는 이유는 단일 언어 위치 (오늘날 컴퓨터에서 32 비트 또는 64 비트)를 공유하면 기계 언어 코드에 많은주의를 기울이지 않으면 캐시 성능이 매우 나빠질 수 있기 때문입니다. 정말로 많은 수의 비트가 있다면 아마도 그만한 가치가 있지만, 그렇지 않으면 네트워크 또는 디스크로 전송할 준비가 될 때 사전 최적화하지 않고 비트를 압축하는 것이 좋습니다.
Bill K

답변:


107

가장 일반적으로 비트 필드 라고하며 자주 듣는 또 다른 용어는 비트 마스크 또는 개별 비트 값 또는 전체 비트 필드를 한 번에 가져 오거나 설정하는 데 사용됩니다.

많은 프로그래밍 언어에는이를 지원하는 보조 구조가 있습니다. @BernhardHiller가 주석에서 언급 한 것처럼 C #에는 플래그 가있는 열거 형이 있습니다 . Java에는 EnumSet 클래스가 있습니다.


4
"비트 필드"는 비트 연산자를 사용하여 수동으로 수행하는 대신 개별 비트를 구조의 필드에 할당 할 수있는 언어 기능을 사용하는 것으로 해석합니다.
Peter Green

22
@PeterGreen 표준 해석과는 다릅니다.
Eric

1
이 경우 레코드 세트 및 배열 처리에 공통적 인 "비트 매핑"또는 "비트 매핑"이 적용될 수 있습니다. 여러 세트에서 공통 요소를 추출 할 때 값이 분해되어 연합 모델의 구성 요소를 식별 할 수 있습니다. 우리는 이것을 8 진 파일 모드 숫자라고 말합니다. 비트 마스크 (모든 마스크)는 필터 인 경향이 있습니다 (IO 포트 및 데이터 방향 레지스터와 동일).
mckenzm

1
C #에는 또한 BitArray임의의 양의 비트를 저장하고 인덱싱 할 수 있습니다 (플래그는 정수 유형으로 제한되고 마스크로 사용되도록 의도 됨).
Luaan

참된; 방금 가장 익숙한 두 가지 구조를 언급했습니다. 아마도 다른 언어로 아마도 수십 개가있을 것입니다.
Glorfindel

20

이상한, 여기에는 약간 다른 용어가 있지만 즉시 생각 나는 단어가 보이지 않습니다 (그리고 그것은 당신의 질문의 제목에 있습니다!)-비트 패킹은 내가 항상 말한 것으로 들었습니다.

나는 이것이 정말로 명백하지만 이상하게도 구글에있을 때 이것이 널리 사용되었지만 공식적으로 정의되지 않은 용어 인 것처럼 보인다고 생각했다 (Wikipedia는 비트 패킹을하는 방법 인 비트 필드로 리디렉션하는 것으로 보이지만 방법). 정의를 검색하면이 페이지로 연결되는 것 같습니다.

http://www.kinematicsoup.com/news/2016/9/6/data-compression-bit-packing-101

SO 목적으로는 좋지 않지만 다음과 같은 간결한 설명을 포함하여 찾을 수있는 가장 좋은 정의 / 설명입니다.


당신은 몇 가지 참조를 제공 할 수 있습니까? 재미있는 용어.
Greg Burghardt

13
비트 패킹은 기술적으로 정확하지만 부울 상태보다 더 일반적인 것을 의미합니다. 일반적으로 가능한 한 가장 적은 수의 비트에 데이터를 저장합니다. 예를 들어, 다른 용도로 사용하면 charchar개의을 하나로 묶어 배열을 압축 할 수 int있습니다.
Izkata

@GregBurghardt 아시다시피, 흥미 롭습니다. C 및 어셈블리에서 프로그래밍을 배웠을 때 80 년대 / 90 년대에 널리 퍼져 있기 때문에 게시 할 때 그것에 대해 생각하지 않았습니다 .Google 검색에서 많은 사람들이 언급했지만, 위키피디아 페이지는 없습니다. . 구글의 첫 번째 대답은 "비트 패킹은 간단한 개념이다. 한 조각의 데이터를 저장하기 위해 가능한 한 적은 비트를 사용하는 것"이다. kinematicsoup.com/news/2016/9/6/…
Bill K

비트 패킹에 대해서도 배웠지 만 명목상 정수 값이 될 때 사용하지 않는 0을 다시 바꾸는 것보다 훨씬 미쳤습니다. 몇 년 전 나는 매개 변수 중 하나를 8 비트 플로트로 저장하는 시스템을 만났습니다. 서명되지 않은 가수의 경우 IIRC 5 비트 (모든 값은 부호를 명시 적으로 저장할 필요가 없음)이고 기본 10 지수의 경우 3 비트입니다. 당시에는 경로가없는 레거시 하드웨어 kludge라고 생각했지만 최근에 기계 학습이 int4 대 int8로 작업을 시작한 결과 FP16에서 일부 워크로드가 감소하는 것을 볼 수있었습니다.
Dan Neely

1
@DanNeely 이런 종류의 작업은 GPU에서도 일반적으로 지원됩니다. 정밀도, 메모리 및 계산 간의 거래는 매우 중요합니다. 이것은 GPU 기반 컴퓨팅에서도 잘 활용되었습니다.
Luaan

14

이를 설명하는 데 사용되는 여러 가지 용어가 있습니다.

대부분의 비트를 "비트 플래그"또는 "비트 필드"라고합니다.
그러나 "비트 필드"는 C와 C ++ 언어의 특정 기능을 나타내지 만 관련이 있지만 정확히 동일하지는 않습니다.

정수 자체는 용도와 환경에 따라 "비트 배열", "비트 세트"또는 "비트 벡터"로 다양하게 언급됩니다.

어느 쪽이든, 비트 세트 / 벡터 / 배열로부터 비트를 추출하는 것은 시프트 및 마스킹을 통해 수행된다.
(즉, 비트 마스크 사용 )


활발하게 사용되는 각 용어의 일부 예 :


그것은 실제로 질문과 관련이 없지만 말하고 싶습니다 : 그 방법이 오류가 발생하기 때문에 비트를 설정하고 지우는 데 덧셈과 뺄셈을 사용하지 마십시오.
(즉 num += 1, 두 번 수행 하면 결과는와 같습니다 num += 2.)

선택한 언어가 제공하는 경우 적절한 비트 단위 연산을 대신 사용하십시오.

packStatesIntoNumber ()
{
  let num = 0
  if (this.stateA) num |= 1
  if (this.stateB) num |= 2
  if (this.stateC) num |= 4
  if (this.stateD) num |= 8
  if (this.stateE) num |= 16
  if (this.stateF) num |= 32
  return num
}

unpackStatesFromNumber (num)
{
  this.stateF = ((num & 32) != 0);
  this.stateE = ((num & 16) != 0);
  this.stateD = ((num & 8) != 0);
  this.stateC = ((num & 4) != 0);
  this.stateB = ((num & 2) != 0);
  this.stateA = ((num & 1) != 0);
}

1
this.stateF = (num & 32) ? true : false등을 num추출하는 동안 변경하지 않아도 됩니다.
Roger Lipscombe

3
@RogerLipscombe 좋은 지적은 코드의 실제 내용을 읽지 않고 +and 의 사용에 반응하는 것입니다 -. 나는 지금 != 0삼항 대신에 더 잘하고 사용 했습니다. 나는 여전히 간결하면서 더 간결하다고 느낍니다.
Pharap
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.