'마스킹 된'비트 세트 증가


81

나는 현재 다음과 같은 문제가 발생한 트리 열거자를 작성하는 중입니다.

설정 비트 즉, 마스크의 하위 집합 어디 마스크 bitsets, 즉 bitsets 찾고 있어요 0000101마스크 1010101. 내가 달성하고 싶은 것은 bitset을 증가시키는 것이지만 마스크 된 비트에 대해서만 가능합니다. 이 예에서 결과는입니다 0010000. 좀 더 명확하게하려면 마스킹 된 비트 만 추출합니다. 즉 0011,이를 증분하고 0100마스크 비트에 다시 배포하여 0010000.

비트 캔과 접두사 마스크의 조합을 사용하여 수동으로 작업을 구현하는 것보다 효율적인 방법을 보는 사람이 있습니까?

답변:


123

비 마스크 비트를 1로 채우면 전달됩니다.

// increments x on bits belonging to mask
x = ((x | ~mask) + 1) & mask;

11
그것은 좋은 속임수입니다 ... 내가 말한 마법은 거의 없습니다. :)
— Eugene Sh.

8
@EugeneSh. 그렇지 않다는 것을 결코 믿지 마십시오.
— zch

24
아마도 OP에는 그들이 수락했기 때문에 중요하지 않을 것입니다. 그들이 경우 한 곳이 필요하면 교체 더 조심해야 할 것이다 x. 아마도 x = (x & ~mask) | (((x | ~mask) + 1) & mask);.
— TripeHound 2017-06-27

2
@TripeHound 그들이 필요하지 않았다면 비트 마스크를 사용하는 것의 요점은 무엇입니까?
— someonewithpc

1
@someonewithpc 무슨 말을 하려는지 잘 모르겠습니다. OP가 인접하지 않은 비트 세트를 증가시켜야하는 이유를 모르기 때문에 원래 값 의 다른 비트가 중요한지 여부를 알 수 없습니다. 예를 들어 원래 값이 0101101(예 : .1.1.0.마스크가 아닌 비트 및 0.0.1.1"카운터"에있는 경우) 필요 하거나 ( 보존하는 동안 0111000의 새로운 "카운터" ) 그냥 허용됩니다. 이 대답 (그리고 아마도 다른 사람들은 확인하지 않았지만)은 후자를 제공합니다. 내 버전이 필요한 경우 전자를 제공해야합니다. 0.1.0.0.1.1.0.0010000
— TripeHound

20

허용되는 답변에 비해 직관적이지는 않지만 3 단계로만 작동합니다.

x = -(x ^ mask) & mask;

이것은 zch에서 제안한대로 확인할 수 있습니다.

  -(x ^ mask)
= ~(x ^ mask) + 1  // assuming 2's complement
= (x ^ ~mask) + 1
= (x | ~mask) + 1  // since x and ~mask have disjoint set bits

그러면 받아 들여진 대답과 동일 해집니다.


2
zch의 대답은 매우 직관적입니다. 그의 명확한 설명 덕분에 바로 그것이 옳다는 것을 알 수 있습니다. 이 답변의 논리는 무엇입니까? 이 공식은 원하는 효과를 내기 위해 어떻게 작동합니까? 나는 발견의 과정, 여기서 통찰력의 본질에 대해 궁금합니다.
— FooF

-(x ^ mask) == (x | ~mask) + 1x가 마스크의 하위 집합 임을 증명하고 내 대답을 참조 하면 확인이 훨씬 더 간단해질 것이라고 생각합니다 .
— zch

5
-(x^mask) == ~((x ^ mask) - 1) == ~(x ^ mask) + 1 == (x ^ ~mask) + 1 == (x | ~mask) + 1. 마지막 방정식은 비트 세트가 분리되어 있기 때문에 성립되고 나머지는 항상 참입니다 (적어도 2- 보완에서는).
— zch

1
이 답변을 도출하기 위해 내가 취한 단계에 대해 궁금한 사람들은 이 페이지를 참조 할 수 있습니다 .
— nglee

5
:이 종종 비트 만지작을하는 사람들과 관련이있는, 같은 최적화하지 않는 것을 지적 어쩌면 가치 godbolt.org/g/7VWXas - 하나 실제로 짧은 컴파일러에 의존 보인다 있지만합니다. 어느 것이 더 빠를 지 또는 차이가 중요한지 알 수 없습니다.
— Leushenko 2017-06-27

7

반복 순서가 그다지 중요하지 않고 감소 작업이 요구 사항을 충족 할 경우 두 가지 작업 만 사용할 수 있습니다.

시작하자

x = mask

이전 값을

x = (x - 1) & mask

x - 1부분은 0이 아닌 마지막 비트를 0으로 변경하고 모든 하위 비트를 1로 설정합니다. 그런 다음 & mask부분은 그들 사이에 마스크 비트 만 남깁니다.


작전 2 개, 좋아요. 그러나 나는 그것이 1을 통과하는 것이 아니라 0을 통해서만 차입을 전파하는 동일한 접근 방식이라고 주장합니다.
— zch

@zch, 맞습니다, 감사합니다. 대답을 다시
— 표현하겠습니다

x가 마스크가 아닌 모든 비트가 지워진 상태로 시작하는 경우에만 작동합니다.
— Jasen

@Jasen, 물론입니다. 그러나 마스크가 아닌 비트를 설정하는 것은 어렵지 않습니다. 그리고 다른 답변에도 비슷한 문제가 있습니다.
— DAle
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.