여기선 정수의 산술경계 점검만을 다룹니다.
경계점검이란 간단한 예로 x를 부호없는 정수라하면 if ( 10 <= x && x <= 20 )과 같은 것들을 말합니다.
이는 if ( x-10 <= 10 )로 단축될 수 있죠. (이는 if ( x <= 20 )와는 다른 표기입니다.)
x가 11일때 x-10: 1
x가 10일때 x-10: 0
x가 9일때 x-10: 0xFFFFFFFFFFFFFFFF
이렇게 되니깐요.
(저자는 비교 후 분기(compare-branch) 또는 비교 후 트랩(compare-trap) 명령만 관여한다는 점, 수량 인덱싱에서 배열 접근 주소 계산에 필요할 수 있다는 점에서 위 조건문보다 효율적이라고 주장하고있습니다.)
보통은 점검하는 경계가 넓을 수록 후자가 유리하겠고, 좁을 수록 전자가 유리하겠죠.
if ( a <= x && x <= b )와 같은 경우엔 a <= b가 보장된 경우엔 if ( x - a <= b - a )로 대체될 수 있겠죠
정리하면 a,b,x의 부호가 있든 없든 다음이 성립합니다. 물론 비교연산은 부호없는 연산이여야합니다.
a <= b -> if ( a <= x && x <= b ) == if ( x - a <= b - a ) == if ( b - x <= b - a )
a <= b -> if ( a <= x && x < b ) == if ( x - a < b - a )
a <= b -> if ( a < x && x <= b ) == if ( b - x < b - a )
a < b -> if ( a < x && x < b ) = = if ( x - a - 1 < b - a - 1) == if ( b - x - 1 < b - a - 1 )
-------
모호한 비트경계에 대하여
if ( ( a <= x && x <= b ) &&
( c <= y && y <= d ) )
와 같은 경우엔 산술적으론 if ( a + c <= x + y && x + y <= b + d )로
바꾸어 쓸 수 있지만, 부호없는 정수일 경우 a + c가 넘치면(overflow) 사용될 수 없는 구문입니다.
또한 ( c <= x <= d ) ( a<= y<=b)와 같은 연산이 될 수 있어 경계가 정확하지않은 방법이니
주위를 요구합니다.
이 같은 경우엔 경계를 나누어야계산이 가능합니다.
a+c가 넘치지 않고, b+d가 넘친다면 0 <= x + y <= 2**32-1, 그렇지 않다면 a+c<=x+y<=b+d
a-d<0이고, b-c>=0이면 0<=x-y<=2**32-1, 그렇지 않다면 a-d<=x-y<=b-c
로 경우를 나누어야합니다.(&&생략, **연산은 제곱연산과 같습니다.)
-------
비트연산으로 모호한 경계점검하기
x^y <= x|y, x&y<=x===y (===연산은 상태가 같은 비트만 켜는 연산입니다. ~(x^y))
max(x,y)<=x|y, min(x,y)>=x&y는 항상 성립하는 부등식입니다.
또한 ~x == 2**32-1-x도 성립하죠
위 표현을 미루어 볼때 a,b,c,d,x,y연산은
max(a,c) <= x|y <= b+d
0 <= x&y <= min(b,d) (책에 나와있는데로 그대로 쓰긴 썼는데 a와 c에 값에 영향을 안받네요.)
0 <= x^y <= b+d
로 쓸 수 있습니다.
(~b <= ~x <= ~a) && (~d <= ~y <= ~c) 같은표현도 가능합니다.
다음번엔 popcount, nlz에 대하여 알아봅시다.
언제가 될진 모르겠네요
잡대컴공이말한 변태의 전형적인 예다
마지막에 갑자기 허들이 높아졌어...
참고로 nlz는 선행 0비트의 개수를 세는 건데요, 그중 한 코드는 158 - (((int)((float)(x & ~(x >> 1)) + 0.5f) >> 23) 입니다.
어떤 새x가 비추하고 텼냐
나 궁금한건데
이런 거 적극적으로 도입하면 속도가 얼마나 빨라져?
2^16개짜리 배열 만들어서 2^16개짜리 비트 캐시 저장해볼려고 한 적은 있는데
예를들어서 8개중에 3개 뽑는 조합이면 0101010이나 00011000이런식으로 저장하는거
뭔소리임?
비트 한 자리당 숫자 하나라고 치고 45비트 들고있으면 6개만 1이고 나머지가 0이면 로또 뽑는거 만들 수 있잖음
예에에전에 동아리에서 로또 알고리즘 짜보는거 해봤는데 그렇게 만듬.
비트한자리 라길레 뭔소린지 했음
그니깐 bool배열 45개만들어놓고 중복없이 랜덤으로 true만들어 가져온다는랑 같은 원리 아님?
ㅇㅇ 근데 bool45개보다 나은점은 - DCW
충분히 작을 경우에 int[1<<14]이런식으로 배열 쓰기 가능 - DCW
비트연산만 죽어라 할거 아니면 요새는 딱히 유의미한 퍼포먼스 차이가 안날텐데.
최대가 45면 6비트만으로 표시할 수 있으니 32비트면 5개까지되고 정수 두 개면 10개까지 가능. 근데 중복처리 방법은 잘 모르겠네
프갤에 흔치 않은 좋은 글입니다. 일반적인 연립부등식처럼 연산이 가능하다는 생각은 못했는데 재밌네요. 이걸로 빅오나 빅오메가를 계산할 수도 있겠군요. 이 때 미지수 차수를 줄일 수 있다면 연산속도도 크게 변할 수 있을 겁니다. 컴파일러가 이런 비교구문을 사람이 안 써도 자동으로 생성하거나 계산해줄 수도 있을 것 같습니다. 실용적으로 응용한다면, IDE에서 IF만 치거나 IF와 비교할 변수 하나만 치면 자동으로 다음의 비교구문이 자동으로 추천되는 겁니다.
주위->주의