1. 오버플로우(overflow)
#include <iostream>
using namespace std;
int main()
{
short s = 1; // 2 bytes (16 bits)
cout << std::pow(2, sizeof(short) * 8 - 1) - 1 << endl;
cout << std::numeric_limits<short>::max() << endl;
cout << std::numeric_limits<short>::min() << endl;
cout << std::numeric_limits<short>::lowest() << endl;
s = 32767;
s += 1;
cout << s << endl;
return 0;
}
// 실행결과
32767
32767
-32768
-32768
-32768
short타입 변수 s를 선언하고 여러 방법으로 short자료형의 최대,최소값을 출력해보았다.
std::pow(2, sizeof(short) * 8 - 1) - 1
pow는 제곱이다. (signed) short는 2바이트 크기이므로 16비트 크기일 것이고 0,1 두가지 경우의 수가 16개가 존재하므로
들어갈수 있는 최대값은 2의 8제곱이라 생각할 수 있다. 근데 왜 (2^(8-1) - 1)로 계산한 것일까?
signed는 양수와 음수를 모두 표현할 수 있는 자료형이므로 맨 앞에 한 비트를 부호 표현하는데 사용해야한다.
그래서 2의 7제곱을 하는게 맞다. 2의 7제곱에서 1을 또 빼준 이유는 0을 표현하기 위함이다.
std::numeric_limits<short>::max()
std::numeric_limits<short>::min()
std::numeric_limits<short>::lowest()
더 쉽게 확인할 수 있는 방법은 Limits 라이브러리가 있다. 컴파일러한테 표현할수 있는 숫자의 범위를 물어보는 것이다.
min과 lowest의 차이는 부동소수점형 파트에서 알아볼 것이다.
그런데 마지막에 s = 32767로 초기화 하고 1을 더했을때는 왜 -32768이 나온 것일까?
short 자료형에서 표현할 수 있는 가장 큰 숫자는 32767이었다. 저장할 수 있는 최대 범위를 벗어났기 때문에 최대값에서 1을 더하면
다시 최솟값부터 시작해버리는 것이다. 이 현상을 오버플로우 라고 한다.
반대로 최소값에서 1을 빼버리면 어떻게 될까? 최대값으로 가버린다. 이건 언더플로우 라고 한다.
최소값과 최대값은 꼬리를 물고 원처럼 이어진 상태라고 볼 수 있다.
2. 부동소수점수 (floating point numbers)
float은 4바이트므로 32비트를 사용한다. 그리고 내부적으로 이 32비트를 세 부분으로 나눈다.
부호부는 1비트를 사용하고 지수부는 8비트를 사용하고 나머지 23비트는 가수부가 사용하게 된다.
부호부가 1이면 음수, 0이면 양수를 의미한다.
가수부는 숫자의 절대값을 2진법으로 표현한 것이다.
지수부는 이 수치에서 bias 값을 빼주어야 한다. 일반적으로 float에서 bias의 값은 127이다.
반대로 계산을 해보자.
−118.625 (십진법)을 IEEE 부동소수점 방식으로 표현해보자.
부호는 음수이므로 sign은 1.
−118.625의 절댓값을 이진법으로 나타내면
1110110.101이 나오게 된다. 이제 소수점을 왼쪽으로 이동시켜 1만 남기게 하면 1.110110101이 된다.
1.110110101에서 맨앞에 1을뺀 소수점의 오른쪽 부분은 가수부가 된다. 부족한 비트 수만큼 0으로 채워 23비트로 만든다.
1.110110101은 1110110.101 x 2^6 이다. 지수는 6이므로, bias 127을 더하면 133이 된다. 133을 이진법으로 표현하면
10000101이 되고, 이 숫자가 지수부이다.
* min()과 lowest()의 차이, 지수표현법
#include <iostream>
#include <limits>
using namespace std;
int main()
{
cout << numeric_limits<float>::min() << endl;
cout << numeric_limits<float>::lowest() << endl;
return 0;
}
output :
1.17549e-38
-3.40282e+38
min()은 부동소수점 표현법에서 일반적으로 표현 가능한 수들 중에서 0이 아닌 가장 작은 값을 반환한다.
만약 부동소수점 표현법과 관계없이 표현하는 숫자의 범위를 보고싶을 때는 lowest()를 사용해야 한다.
여기서 e-38과 e+38은 지수 표현법이다. 예제로 설명하면
#include <iostream>
using namespace std;
int main()
{
cout << 3.14 << endl;
cout << 0.314e+1 << endl;
cout << 0.0314e+2 << endl;
cout << 31.4e-1 << endl;
return 0;
}
결과는 모두 3.14이다. e+1은 10의 1승, e+2는 10의 2승이다.
큰 숫자를 많이 다루게 되면 지수 표현법을 사용하는게 편리할 수 있다.
'C++' 카테고리의 다른 글
3-2. C++ 비트단위 연산자(shift,AND,OR,XOR) (1) | 2024.01.29 |
---|---|
3-1. C++ 연산자(콤마 연산자, 삼항 연산자), 이진법 (0) | 2024.01.29 |
2-1. C++ 변수와 기본 자료형 (1) | 2024.01.26 |
1-2. C++의 기초 (namespace, 전처리기) (12) | 2024.01.24 |
1-1. C++의 기초 (입출력 스트림, 헤더파일 만들기, 헤더 가드의 필요성) (13) | 2024.01.24 |