부동 소수점

Jaemyeong Lee·2024년 7월 31일
0

FastCampusC++

목록 보기
3/78

부동소수점 개요

부동소수점은 실수를 표현하는 방법 중 하나로, 소수점의 위치를 고정시키지 않고 지수부와 가수부로 나누어 표현합니다. 이를 통해 매우 큰 수나 매우 작은 수를 효율적으로 표현할 수 있습니다.

부동소수점 형식

타입 지정자크기 (비트)지수부 (비트)가수부 (비트)
float32823
double641152
long double64 ~ 128--

부동소수점의 메모리 구성

부동소수점 수는 부호, 지수부, 가수부로 구성됩니다.

예를 들어, -118.625를 부동소수점으로 표현하면 다음과 같습니다:

  • 부호: 1
  • 지수부: 10000101
  • 가수부: 11011010100000000000000

부동소수점 코드 예제

#include <iostream>
#include <cfloat>
#include <cstring> // memcpy를 사용하기 위해 필요

using namespace std;

int main()
{
    {
        // 부동소수점의 기본 연산
        float num0 = 1.5f;
        float num1 = num0 * 1.5f;
        float num2 = num0 / 2.0f;
        float num3 = num0 - 3.0f;

        cout << "num0: " << num0 << endl; // 1.5
        cout << "num1: " << num1 << endl; // 2.25
        cout << "num2: " << num2 << endl; // 0.75
        cout << "num3: " << num3 << endl; // -1.5
    }

    {
        // 부동소수점 자료형의 크기
        float fnum = 1.0f;
        double dnum = 1.0;
        long double ldnum = 1.0;

        cout << "float: " << sizeof(fnum) << " bytes" << endl;  // 4
        cout << "double: " << sizeof(dnum) << " bytes" << endl; // 8
        cout << "long double: " << sizeof(ldnum) << " bytes" << endl; // 8

        cout << "sizeof(1.0f): " << sizeof(1.0f) << " bytes" << endl; // float
        cout << "sizeof(1.0): " << sizeof(1.0) << " bytes" << endl;   // double
        cout << "sizeof(1.0L): " << sizeof(1.0L) << " bytes" << endl; // long double
    }

    // 정밀도 변경
    cout.precision(64);

    {
        // 부동소수점의 메모리 상의 표현
        unsigned int uintNum;
        float fnum = -118.625f;
        memcpy(&uintNum, &fnum, sizeof(fnum));

        cout << "Memory representation of -118.625f: " << uintNum << endl; // 3270328320
        cout << "Value: " << fnum << endl;  // -118.625

        fnum = 0.231689453125f;
        memcpy(&uintNum, &fnum, sizeof(fnum));

        cout << "Memory representation of 0.231689453125f: " << uintNum << endl; // 1047347200
        cout << "Value: " << fnum << endl; // 0.231689453125
    }

    {
        // 부동소수점 비교 연산의 문제점
        float num0 = 0.1f;
        float num1 = 0.02f * 5.0f;

        if (num0 == num1)
            cout << "Equal 1" << endl; // 실행 안 됨
        if (num0 == 0.1f)
            cout << "Equal 2" << endl; // 실행 됨
        if (num0 == 0.1)
            cout << "Equal 3" << endl; // 실행 안 됨
        if (num0 == 0.1L)
            cout << "Equal 4" << endl; // 실행 안 됨

        cout << "num0: " << num0 << endl; // 0.1 아님
        cout << "num1: " << num1 << endl; // 0.1 아님

        cout << "0.1f: " << 0.1f << endl;
        cout << "0.1: " << 0.1 << endl;
        cout << "0.1L: " << 0.1L << endl;

        num0 = 1.0f;
        num1 = 0.0f;
        for (int i = 0; i < 1000; i++)
            num1 = num1 + 0.001f;
        if (num0 == num1)
            cout << "Equal 0" << endl;  // 실행 안 됨
        if (fabsf(num0 - num1) <= FLT_EPSILON)
            cout << "Equal 1" << endl;  // 실행 안 됨

        num0 = 1.0f;
        num1 = 0.0f;
        for (int i = 0; i < 10; i++)
            num1 = num1 + 0.1f;
        if (num0 == num1)
            cout << "Equal 2" << endl;  // 실행 안 됨
        if (fabsf(num0 - num1) <= FLT_EPSILON)
            cout << "Equal 3" << endl;  // 실행 됨
    }

    {
        // Epsilon 유도
        unsigned int intNum0 = 0b00111111100000000000000000000000;
        float fNum0;
        memcpy(&fNum0, &intNum0, sizeof(intNum0));
        cout << "fNum0: " << fNum0 << endl; // 1.0f

        unsigned int intNum1 = 0b00111111100000000000000000000001;
        float fNum1;
        memcpy(&fNum1, &intNum1, sizeof(intNum1));
        cout << "fNum1: " << fNum1 << endl; // 1.00000011920928955078125f

        float epsilon = fNum1 - fNum0;
        cout << "Epsilon: " << epsilon << endl;
        cout << "FLT_EPSILON: " << FLT_EPSILON << endl;
    }

    {
        // 1.0f에서 더할 수 있는 가장 작은 수 구하기
        float fNum0 = 1.0f;
        float fNum1;
        unsigned int intNum1 = 0b00110100000000000000000000000000;
        memcpy(&fNum1, &intNum1, sizeof(intNum1)); // Epsilon

        cout << "fNum0: " << fNum0 << endl;
        cout << "fNum1 (Epsilon): " << fNum1 << endl;
        cout << "fNum0 + fNum1: " << fNum0 + fNum1 << endl; // 더한 값 출력
    }

    {
        // 1.0f에서 더할 수 있는 가장 작은 수보다 더 작은 수를 더 할 때
        float fNum0 = 1.0f;
        float fNum1;
        unsigned int intNum1 = 0b00110011100000000000000000000000;
        memcpy(&fNum1, &intNum1, sizeof(intNum1)); // 매우 작은 수

        cout << "fNum0: " << fNum0 << endl;
        cout << "fNum1: " << fNum1 << endl;
        cout << "fNum0 + fNum1: " << fNum0 + fNum1 << endl; // 더한 값이 나오지 않음
    }

    {
        // 1.0f를 더했을 때 문제가 없이 더해지는 수
        float fNum0 = 1.0f;
        float fNum1;
        unsigned int intNum1 = 0b01001011000000000000000000000000;
        memcpy(&fNum1, &intNum1, sizeof(intNum1)); // 큰 수

        cout << "fNum0: " << fNum0 << endl;
        cout << "fNum1: " << fNum1 << endl;
        cout << "fNum0 + fNum1: " << fNum0 + fNum1 << endl; // 더한 값 출력
    }

    {
        // 1.0f를 더했

을 때 더해지지 않는 수
        float fNum0 = 1.0f;
        float fNum1;
        unsigned int intNum1 = 0b01001011100000000000000000000000;
        memcpy(&fNum1, &intNum1, sizeof(intNum1)); // 매우 큰 수

        cout << "fNum0: " << fNum0 << endl;
        cout << "fNum1: " << fNum1 << endl;
        cout << "fNum0 + fNum1: " << fNum0 + fNum1 << endl; // 더한 값이 나오지 않음
    }

    {
        // 최대값 구하기
        float fnum;
        unsigned int uintNum = 0b01111111011111111111111111111111;
        memcpy(&fnum, &uintNum, sizeof(uintNum));

        cout << "FLT_MAX: " << FLT_MAX << endl;
        cout << "fnum (max): " << fnum << endl;
    }

    {
        // NaN 구하기
        float fnum;
        unsigned int uintNum = 0b01111111111111111111111111111111;
        memcpy(&fnum, &uintNum, sizeof(uintNum));

        cout << "fnum (NaN): " << fnum << endl;
    }

    {
        // 무한대 구하기
        float fnum;
        unsigned int uintNum = 0b01111111100000000000000000000000;
        memcpy(&fnum, &uintNum, sizeof(uintNum));

        cout << "fnum (infinity): " << fnum << endl;
    }

    {
        // TRUE_MIN
        float fnum;
        unsigned int uintNum = 0b00000000000000000000000000000001;
        memcpy(&fnum, &uintNum, sizeof(uintNum));

        cout << "FLT_TRUE_MIN: " << FLT_TRUE_MIN << endl;
        cout << "fnum (true min): " << fnum << endl;
    }

    {
        // MIN
        float fnum;
        unsigned int uintNum = 0b00000000100000000000000000000000;
        memcpy(&fnum, &uintNum, sizeof(uintNum));

        cout << "FLT_MIN: " << FLT_MIN << endl;
        cout << "fnum (min): " << fnum << endl;
    }
}

주요 개념 설명

  1. 부동소수점의 기본 연산:

    • 기본적인 부동소수점 연산을 수행하고 출력합니다.
  2. 부동소수점 자료형의 크기:

    • float, double, long double 자료형의 크기를 확인합니다.
    • 리터럴 접미사를 통해 자료형을 지정할 수 있습니다 (1.0f, 1.0, 1.0L).
  3. 부동소수점의 메모리 상의 표현:

    • 부동소수점을 메모리에서 어떻게 표현하는지 확인합니다.
    • memcpy를 사용하여 부동소수점 값을 메모리에서 정수로 변환해 출력합니다.
  4. 부동소수점 비교 연산의 문제점:

    • 부동소수점 비교 연산에서 발생할 수 있는 문제를 설명합니다.
    • 부동소수점 값은 근사값으로 저장되므로, 직접 비교시 문제가 발생할 수 있습니다.
  5. Epsilon 유도:

    • Epsilon은 1보다 큰 float 값 중 가장 작은 수로, 두 부동소수점 값의 차이를 이용해 유도할 수 있습니다.
  6. 부동소수점의 최대값, NaN, 무한대, 최소값:

    • 부동소수점의 최대값, NaN, 무한대, TRUE_MIN, MIN 값을 출력하고 설명합니다.
profile
李家네_공부방

0개의 댓글