강좌 & 팁
2.5 실수형
실수를 나타내는 자료형에는 float형, double형, long double형이 있으며 크기와 범위는 다음 표와 같다.
2.5.1 실수 표현 문제 발생 이유 및 오차 발생 이유 !
다음 코드를 작성하고 출력 결과를 확인해 보자
#include <stdio.h>
int main(void)
{
int no = 12;
float ave = 323.1234f;
printf(" %d + %f = %f \n", no, ave, no+ave);
printf(" %d + %10.4f = %10.5f \n", no, ave, no+ave); //출력 자리수 조절.
return 0
}
실행 결과
우리는 변수 ave에 324.1234를 할당했는데, 출력 결과에서는 335.12341으로 나온다.
소수 부분에 값이 추가 되었다.컴파일 과정이나 실행 과정에서 error 이나 warning은 발견되지 않았다.
double로 작성된 다음 예제를 살펴보자.
#include <stdio.h>
int main(void)
{
float pi1 = 3.141592653589793f;
double pi2 = 3.141592653589793;
printf(" float 형의 pi 값 : %f\n", pi1);
printf(" double 형의 pi 값 : %f\n", pi2);
printf(" float 형의 pi 값 : %30.25f\n", pi1);
printf(" double 형의 pi 값 : %30.25f\n", pi2);
return 0;
}
float는 지원하는 자리수 보다 큰범위의 소수점 범위가 저장되어, 소수점 7번째 자리부터 잘못된 값을 출력하고 있고, double는 float에 비해 더 큰 소수점 범위를 지원하므로 3.131592까지는 정확하나 1이 더 붙어서 출력되었다!
이런 문제가 발생하는 이유는 컴퓨터에서 10진수를 2진수로 변환할 때 발생하는 구조적인 문제이다.
실수의 표현 방식
실수는 다음과 같이 두가지 방식을 사용해 표현한다.
고정 소수점 방식 123.456 (정수 X 소수)
고정 소수점은 우리가 흔히 사용하는 방식이고 부동 소수점은 부호부분과 가수부 및 지수부의 세부분으로 나누어 표현하는 방식이다.
실수의 저장 형식은 다음과 같다.
- 실수 1.0을 2진수로 변환하고, float type으로 저장되는
과정
부동소수점 방식 -> 1.0 * 2^0
부호
비트(1bit) : 0
지수 비트(8bit) : 0 + 127 = 127,
이진수 0111 1111
(현재는 지수가 0 그리고, 지수에 127을 더해서 저장)
※ 127을 더하는 이유 : 0.0345는 양수이다. 하지만,
지수로 표현하면 3.45 * 10^ -2 이므로 지수가 음수가 된다. 따라서, 8bit를 사용하는 지수부분에서 부호bit를 만드는 번거로움을
피하기 위해, 기본적으로 127을 더한다.
가수비트(23bit) : 1, 그러나 1은 저장하지 않는다.
(2진수 부동소수점 표현에서는 맨처음이 반드시 1이다. 따라서 1을 저장하지 않음.)
따라서 1.0의
2진수 float type 표현은 0 011 1111 1000 0000 0000
0000 0000
0000
--------------------------------------------------------------------------------------
비교 : 정수 1이 4byte 공간에 저장될 때는 1byte는 부호 bit, 나머지는 데이터 저장에 쓰인다.
따라서, 정수 1은 0
000 0000 0000 0000 0000 0000 0000 0001 로 저장된다.
* 정수 -1의 2진수 형태.
첫째, 정수
1의 각 bit를 반전시킨다.
1 111 1111 1111 1111 1111 1111 1111 1110
둘째, 반전시킨 2진수 값에 1을 더한다.
1 111 1111 1111 1111 1111 1111 1111 1111
이를 2의 보수 방법이라 한다. 최상위
bit 1음 -(음수)를
의미한다.
--------------------------------------------------------------------------------------
『오차 없이 실수를 사용하고 싶을 땐』
1. float의 가수 정밀도는 6~7 자리.
2. double의 가수 정밀도는 15~16자리이다
정밀도를 올리면 된다.
//실수를 화면에 출력하는 프로그램
#include <stdio.h>
int main()
{
float fnumber = 45000.67; //소수점 이하는 2진수로 변환이 잘 안됨.
printf("%f\n",fnumber);
printf("%9.4f\n",fnumber); //9는 전체자리수 이고 4는 소수부분이다.
//최소자리수가 9이므로 145000.67도 다표시 된다.
printf("%e\n",fnumber);
return 0;
}
ex)16.000 과 16은 다르게 취급된다.
16.000은 16.000까지는 정확한 수이며 그뒤의 자리부터 바뀐다는 말이며
16은 16까지가 정확한 수라고 하는 것 이다.
지금 사용하는 컴파일러 에서는 int , long 이 4바이트로 같지만 다를수도 있다.