[CSAPP] DataLab
1. int bitNor(int x, int y)
Nor 연산은 두 값이 0일 때만 1을 반환한다. not과 and 연산자가 있으므로 ‘~(x|y)’를 적용하여 ‘~x & ~y’로 표현할 수 있다.
2. int allEvenBits(int x)
Nor 연산은 두 값이 0일 때만 1을 반환한다. not과 and 연산자가 있으므로 ‘~(x|y)’를 적용하여 ‘~x & ~y’로 표현할 수 있다.
3. unsigned float_abs(unsigned uf)
절댓값을 반환하기 위해서는 최상위 비트의 부호가 양수가 되어야 한다. IEEE 754에 따라 float의 경우 부호비트, 지수비트, 가수 비트로 나뉘는데 비트를 어떻게 할당하느냐에 따라 NaN 값이 발생할 수 있어 이를 처리해주어야 한다.
지수 비트가 전부 1이고, 가수 비트 부분에 1이 하나라도 있는 경우 NaN값이다. allEvenBits 문제 해결에서 mask 아이디어를 얻어 부호 비트만 0이고 나머지가 1인 mask1을, 지수 비트들만 1이고 나머지가 0인 mask2를, 가수 부분들만 1이고 나머지가 0인 mask3을 만든다.
만약 mask2와 uf를 and연산하여 반환한 값이 mask2와 같다면 uf의 지수 비트가 모두 1이라는 것이고, mask3과 and연산하여 반환한 값이 0이 아닌 어떤 수라면 NaN조건을 충족하여 uf를 그대로 return하고, 아닌 경우 mask1을 씌워 부호비트를 0으로 만든, 즉 uf의 절댓값을 return해준다.
4. int isGreater(int x, int y)
수 크기의 대소비교를 위해 두 수의 차를 구하고 그것이 양수인지 음수인지 판단하고 싶다. 그런데 조건 상 뺄셈 연산자를 사용할 수 없다. 그래서 이진수의 특성을 이용하여 수 하나(y)를 음수로 만들고 두 수를 더하는 방법을 사용할 것이다. 음수로 만들기 위해 2의 보수로 만들고 1을 더해줄 것인데, 이는 ‘~y+1’로 표현할 수 있다. 이를 x와 더한 후(x+~y+1), 이 값을 31만큼 오른쪽으로 shift하여 부호를 나타내는 최상위 비트만 남게 한다(C의 경우 최상위 비트를 유지하므로 0xFFFFFFFF 또는 0x00000000이 나타날 것이다). 이렇게 나온 수에 논리연산자 ‘!’를 적용하여 return하고, 이 값이 1일 경우 x>y(차가 양수, !0x00 -> True) , 0일 경우 x<=y이다(차가 음수, !0x01 -> False)
…로 끝내려고 했는데 x와 y의 값이 둘 다 0x80000000인 경우가 테스트 케이스에 있었다.
2의 보수로 바꿔 1을 더하면 오버플로우 문제가 생긴다. 원래의 값이 바뀌지 않는 것이다.
그래서 이 경우를 해결하기 위해 두 수가 같은지 여부를 확인하는 int형 변수 equal을 만들어 x와 y를 XOR연산 한 결과를 ‘!’로 뒤집어 넣어준다(같으면 1, 다르면 0). msb와 equal값을 or연산해서 둘 다 0인 경우에만 1을 return하도록 했다.
…로 끝내려고 했는데 테스트 케이스에 0x80000000과 0x7FFFFFFF의 크기 비교를 하는 경우도 있었다. y의 부호를 뒤집어 더하는 과정에서 또 오버플로우가 난 것이다. 이에 각각의 부호 비트를 따로 구하여 x와 y의 부호가 다른 경우에 대한 처리를 했다.
diffSign으로 부호가 다른지 확인하고, 부호가 다를 경우 무조건 양수가 크므로 x가 양수, y가 음수인 경우에만 diffSignRes 값을 1로 설정한다. sameSignRes는 부호가 같을 경우 msb값을 따져 설정한다. 각각의 부호 비트를 따로 구하여, 부호가 다를 경우와 같을 경우에 대해 따로 계산한 결과를 or하고, 두 수가 동일했는지 여부를 체크하여(&!equal) return한다.
5. int addOK(int x, int y)
오버플로우가 발생하는 조건 두 가지가 있다 (양수+양수=음수, 음수+음수=양수.)
x,y의 최상위 비트로 좌변의 양수/음수를 판단하고(a,b), x+y의 최상위 비트로 우변의 결과 조건을 판단할 수 있게 한다(res). 이 때 최상위 비트만 남기기 위해 x,y,x+y를 각각 31bit만큼 shift하여 a,b,res를 각각 만들었다. a와 b를 XOR연산하여 같은 부호의 수끼리 더한다는 좌변 조건을 만들고(같은 부호일 때 1을 return하게 !로 논리값 뒤집기), a와 res를 XOR연산하여 x+y 값의 부호가 좌변의 부호와 같은지 확인하는 우변 조건을 만들고, and연산하여 overflow 여부를 파악. overflow의 경우에만 1&1의 상황으로 항상 1이 반환되기에 !로 논리값을 뒤집어 조건에 맞게 return한다.
6. int bang(int x)
이진수 x에 1이 하나라도 들어갈 경우 !x는 0이고, 아닐 경우 1이 된다.
이에 OR 연산의 성질을 사용할 수 있다. OR연산은 두 수가 0일 경우에만 0을 반환하는 특수성이 있으므로, -x를 구하여 x와 서로 연산한 후 최상위 비트를 봤을 때 0이면 원래의 수도 0인 것이고, 0이 아닌 수라면 최상위 비트는 1일 수밖에 없다. 이를 31bit만큼 오른쪽으로 shift하여 최하위 비트로 만들어주고 AND연산을 적용하여 1인지 0인지 판단. 논리값을 뒤집는 것이 함수의 목적이므로 1과 XOR연산을 한 값을 return하면 된다.
Leave a comment