[소소한 개발 일지] serverless-next.js를 사용한 배포에서 새로운 Role이 계속 생성되는 문제 해결하기
C/C++ 공부하기 #1 진법 공부
2019-01-12
Explanation
저는 인터프리터 언어만 사용하다보니 예전부터 컴파일 언어에 이해가 부족함을 자주 생각하곤 했답니다. 그리고 최근에는 웹어셈블리에 관심을 가지고 있다보니 C/C++을 공부해보면 좋겠다 생각을 갖게 되었어요.
그래서 요즘 조금씩 C언어에 대해서 공부하고 있는데요. C언어 기초 책을 보며 공부하다가 제가 잘 모르고 그냥 지나쳤던 부분들, 그리고 까먹기 쉬운 부분들을 메모해 두려합니다.
오늘은 그 첫번째로 진법입니다.
옛날에 자바스크립트를 공부할때에도 이진법에 관한 부분과 비트 연산자에 관한 부분이 책 앞부분에 있었던 것으로 기억합니다. 하지만 ‘이걸 왜써?’ 라는 마음으로 넘겨버렸답니다.
사실 아직까지도 일하며 이진법을 직접적으로 고민해야 한 적은 없지만.. C언어를 공부하는 건 메모리에 관한 부분에 대해 깊게 알고 싶어서 이기도 하고, 개발자로써 이진법을 잘 모른다는건 좀.. 창피한 일인거 같아서 예제 문제들을 하나하나 풀어보았습니다.
1-1. 문제1
1~20까지 2진수, 8진수, 16진수로 표현해 봅니다.
10진수 / 2진수 / 16진수 / 8진수
1 / 1 / 1 / 1
2 / 10 / 2 / 2
3 / 11 / 3 / 3
4 / 100 / 4 / 4
5 / 101 / 5 / 5
6 / 110 / 6 / 6
7 / 111 / 7 / 7
8 / 1000 / 8 / 10
9 / 1001 / 9 / 11
10 / 1010 / a / 12
11 / 1011 / b / 13
12 / 1100 / c / 14
13 / 1101 / d / 15
14 / 1110 / e / 16
15 / 1111 / f / 17
16 / 10000 / 10 / 20
17 / 10001 / 11 / 21
18 / 10010 / 12 / 22
19 / 10011 / 13 / 23
20 / 10100 / 14 / 24
1-2. 문제2
1비트가 표현할 수 있는 데이터의 수는 0과 1 두 개입니다. 그렇다면, 2비트, 4비트, 1바이트, 4바이트로 표현할 수 있는 데이터 수는?
1비트 = 2
2비트는 2 * 2 = 4
4비트는 2 * 2 * 2 * 2 = 16
1바이트는 8비트 = 28 = Math.pow(2, 8) = 256
4바이트는 32(8 * 4)비트 = 232 = Math.pow(2, 32) = 4294967296
1-3. 문제3
다음의 2진수는 각각 10진수로 얼마가 될까요
0000001 = 20 = 1
0000100 = 22 = 4
0010000 = 24 = 16
1-4. 문제4
다음의 2진수는 각각 10진수로 얼마가 될까요
0101001 = 20 + 23 + 25 = 1 + 8 + 32 = 41
실제로 C언어에서는 하나의 정수를 4바이트로 표현하지만, 간편한 이해를 위해 1바이트라고 가정하고, 정수를 표현하는 1바이트의 메모리에 가장 왼쪽에 있는 비트는 부호비트라고 하며 양수 일때는 0, 음수 일때는 1입니다.
하지만 -5를 표현할 때 양수 5를 나타내는 이진수 00000101에서 부호비트를 1로 바꾸어 10000101 이렇게 표현하지 않습니다. (00000101 + 10000101 !== 0)
-5를 표현하는 방법은
5를 나타내는 2진수 0000101 를 1의 보수를 구한 후(= 1111010) 1을 더 합니다.(= 1111011) 다시 이 값이 -5인지 확인하기 위해 00000101 + 1111011 을 하면 100000000이 되는데. 여기에서 올림수 1은 버려지기 때문에 합의 결과는 00000000이 됩니다.
이 과정을 ‘2의 보수법’ 이라고 합니다.
2-1. 문제5
정수를 1바이트로 표현한다고 가정하고 음의 정수 10101001는 10진수로 얼마 일까?
앞에서 이야기한 2의 보수법으로 바꾸어야 하니,
10101001의 1의 보수를 취하면 01010110 에서 1을 더하면 01010111 이니까 이걸 10진수로 바꾸면
20 + 21 + 22 + 24 + 26 = 1 + 2 + 4 + 16 + 64 = 87 = -87
적은 비트의 수를 가지고 넓은 범위의 실수를 표현하기위해 하나의 아래와 같은 식을 정의했다고 한다.
±(1.m)x2e-127
(다행이도 이 식이 어떻게 도출된 것인지 책에 자세히 나오지 않았습니다. [휴…])
그런데 이진법으로 소수를 표현하는 것 자체가 아주 가까운 근사치값으로 표현하는 것이기 때문에 정확한 값을 표현하지 못하는 경우가 있습니다. 그리고 그러한 오차를 가리켜 ‘부동 소수점 오차’ 라고 합니다.
아래는 하나의 예 입니다.
1 2 3 4 5 6 7 8 9 10 11 12 |
#include <stdio.h> int main() { int i; float num = 0.0; for(i=0; i<100; i++) { num += 0.1; } printf("%f", num); return 0; } // 10.000002 |
이는 자바스크립트에서 0.1 + 0.2 가 0.30000000000000004 를 출력하는 것과 같은 상황을 의미합니다.
그런데 C/C++ 에서는 0.1 + 0.2 = 0.300000 가 출력 되는데요.
결괏값의 차이가 있는 것은 C/C++ 과 Javascript가 채택한 표준이 달라서 그런가? 했는데,
검색해보니 둘 모두 IEEE 754 부동 소수점 표준을 따르는 것 같습니다.
참고: https://en.wikipedia.org/wiki/Double-precision_floating-point_format
조금 더 알아보니 C/C++ 에서도 출력할 때 소수점 자리수의 제한을 넓히면 Javascript와 동일하게 값을 출력하는 것을 확인 할 수 있었습니다.
1 2 3 4 5 6 7 8 |
#include <stdio.h> int main() { printf("%.17f", 0.1 + 0.2); return 0; } // 0.30000000000000004 |