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


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.