2.5 실수형

실수를 나타내는 자료형에는 float형, double형, long double형이 있으며 크기와 범위는 다음 표와 같다.

실수형05.jpg

 

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
}

실행 결과

float01.png

 

우리는 변수 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;
}

 

실수형02.jpg

 

float는 지원하는 자리수 보다 큰범위의 소수점 범위가 저장되어, 소수점 7번째 자리부터 잘못된 값을 출력하고 있고, double는 float에 비해 더 큰 소수점 범위를 지원하므로 3.131592까지는 정확하나 1이 더 붙어서 출력되었다!

이런 문제가 발생하는 이유는 컴퓨터에서 10진수를 2진수로 변환할 때 발생하는 구조적인 문제이다.

 

실수의 표현 방식

실수는 다음과 같이 두가지 방식을 사용해 표현한다.

 

고정 소수점 방식 123.456 (정수 X 소수)

 

실수형04.jpg

고정 소수점은 우리가 흔히 사용하는 방식이고 부동 소수점은 부호부분과 가수부 및 지수부의 세부분으로 나누어 표현하는 방식이다.

실수의 저장 형식은 다음과 같다.

실수형02.jpg

 

- 실수 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;
}

실수형03.jpg

 

ex)16.000 과 16은 다르게 취급된다.

16.000은 16.000까지는 정확한 수이며 그뒤의 자리부터 바뀐다는 말이며

16은 16까지가 정확한 수라고 하는 것 이다.

지금 사용하는 컴파일러 에서는 int , long 이 4바이트로 같지만 다를수도 있다.