[백준] 1008 (부동소수점,float,double, 출력 형식)

YUN·2025년 8월 23일

C++

목록 보기
4/85

아,,씁다

이 문제는 부동소수점과 실수 자료형+오차 범위, 출력 형식 에 대해서 정확히 알아야 풀 수 있는 문제이다.

1. 부동 소수점과 실수 자료형

C 언어에서 float과 double 자료형은 실수를 부동소수점(Floating Point) 방식으로 표현한다.

±1.xxxxxxxx*2^(xxxx)

이 방식은 IEEE 754 표준을 따르며, 정밀도(Precision)표현 가능한 범위(Range)가 자료형에따라서 달라진다.

부동 소수점에서 지수 부분은 표현 범위를 나타내고,
(2가 1번 곱해질때마다 가수 부분은 오른쪽으로 1 bit씩 밀린다)

가수 부분은 정밀도를 나타낸다.

(1) float

float의 경우 부호 비트가 1bit, 지수가 8bit, 가수가 23 bit 이다.

±1.xxxxxxxx*2^(xxxx) 로 표준화해서 나타낸 다음 지수에 넣는다.'
(위의 형식에서 가수부분은 2진수이고, 지수 부분은 10진수이다)

이때 주의할 점은

  • 지수는 그대로 2진수로 저장되고

  • 지수 부분은 양의 바이어스 (127)이 더해져서 2진수로 저장된다.

부동 소수점은 가독성을 위해서 매핑 방식을 바꾸기 때문이다.

(마이크로프로세서 수업에서 배운 바로는 그렇다.)

예시

  • 양수 -> 부호비트 0
  • 지수가 6 -> 6+127 = 133 을 저장해야함 -> 10000101
  • 가수는 001111 -> 그대로 001111 저장

  • 음수 -> 부호비트 1
  • 지수가 2 -> 2+127 = 129 을 저장해야함 -> 10000001
  • 가수는 101 -> 그대로 101 저장

정확도

결론부터 말하자면 float 자료형의 정확도는 약 7자리(소수점 앞, 소수점 뒤 모두 포함해서)이다.

암묵적 1 을 포함하여 가수가 총 24bit이다.

2^(24)=16,777,216=10^(7.22..) 이다.

총 0~10^(7.22..)까지의 수 만큼을 표현할 수 있다는 것이다.
(지수는 가수를 왼쪽이나 오른쪽으로 1bit 씩 미는 역할 밖에없다. 실제로 의미있는 수는 오로지 가수에 의해서 결정된다)

다시말해, float 자료형은 10진수로 약 7자리 정도를 정확히 표현할 수 있다

예를들어 보자.

#include <stdio.h>

int main() {
    float f = 1234567.0f;    // 7자리
    float f2 = 12345678.0f;  // 8자리

    printf("f  = %.0f\n", f); // 1234567 출력
    printf("f2 = %.0f\n", f2); // 12345680 출력 (8번째 자리에서 반올림)

    return 0;
}

즉 float에 8자리 이상의 실수를 저장하면, 8번째 자리에서 반올림 되어 저장된다.

(2) double

double 의 경우 부호 비트가 1bit, 지수가 11bit, 가수가 52 bit 이다.

±1.xxxxxxxx*2^(xxxx) 로 표준화해서 나타낸 다음 지수에 넣는다.'
(위의 형식에서 가수부분은 2진수이고, 지수 부분은 10진수이다)

이때 주의할 점은

지수는 그대로 2진수로 저장되고

지수 부분은 양의 바이어스 (1023)이 더해져서 2진수로 저장된다.

부동 소수점은 가독성을 위해서 매핑 방식을 바꾸기 때문이다.

(마이크로프로세서 수업에서 배운 바로는 그렇다.)

정확도

결론부터 말하자면 double 자료형의 정확도는 약 15자리(소수점 앞, 소수점 뒤 모두 포함해서)이다.

암묵적 1 을 포함하여 가수가 총 53bit이다.

2^(53)=16,777,216=10^(15.95..) 이다.

총 0~10^(15.95..)까지의 수 만큼을 표현할 수 있다는 것이다.
(지수는 가수를 왼쪽이나 오른쪽으로 1bit 씩 미는 역할 밖에없다. 실제로 의미있는 수는 오로지 가수에 의해서 결정된다)

다시말해, double 자료형은 10진수로 약 15~16자리 정도를 정확히 표현할 수 있다

double에 15~16자리 이상의 실수를 저장하면, 15~16번째 자리에서 반올림 되어 저장된다. **

2. 입,출력 형식

(1) <iostream>

🧐 std::cout.precision(n)

std::cout.precision(n)

하면

실수 전체 자리수를 n으로 고정해서 출력한다.

예를들어

double a = 1234.5678;
std::cout.precision(7);
 
std::cout << a;	// 1234.5678 에서 반올림 된 1234.568 이 출력 된다.

참고로 앞서

using namespace std;

수행한 경우, 그냥

cout.precision(n);

만 해줘도된다.

🧐 std::cout << std::fixed;

std::cout << std::fixed;

하면 앞서 std::cout.precision(n) 으로 설정했던,

실수 전체 자리수를 n으로 고정해서 출력하던 것을

소수점 아래n자리만큼 고정해서 출력하는 것

으로 변경한다.

참고로 앞서

using namespace std;

수행한 경우, 그냥

cout << fixed;

만 해줘도된다.

🧐 std::cout.unsetf(ios::fixed);

std::cout.unsetf(ios::fixed);

을 하면, 고정 소수점으로 표현하는 것을 해제하고 다시

실수 전체 자리수를 n 으로 고정해서 출력

하도록 변경한다.

(3) 정수를 입력받는 경우 실수로 받아도된다.

문제에서는 정수를 입력 받는 것으로 되어있다.

정수를 실수 자료형의 변수에 저장할 수 있다.

생각해보면 당연하다, 실수가 정수보다 큰 개념이니까 실수 자료형에 정수를 저장할 수 있는 것은 너무나도 당연한 소리이다.

(2) <stdio.h> or <cstdio>

🧐 형식 지정자

float 과 double

float의 경우 형식 지정자를 %f로 사용했다.

double의 경우 형식 지정자를 %lf로 사용해야한다.

소수점 몇번 째 자리까지 표현?

float a = 5.2334;
printf("%.2f", a); //5.23 출력

double a = 5.2334;
printf("%.2lf", a); //5.23 출력

위와 같이 실수를 출력할 때, %.nf 또는 %.nlf로 소수점 몇 번째 자리까지 출력할 것인지를 지정해줄 수 있다.

3. 풀이

(1) <iostream>

#include <iostream>
using namespace std;

int main() {
    double a,b;
    
    cin >> a >> b;
    
    cout.precision(10);
    cout << fixed;
    
    cout << a/b;
    
    
    return 0;
}

이런 조건이 존재한다.

출력값의 최댓값이 9 이다.

float을 사용하면 예를들어 (이런 수는 나오지 않겠지만) 8.155488895 과 같은 수를 저장하지 못하고 8.155489 이렇게 반올림해서 저장해버린다.

즉 오차가 10^(-9) 보다 더 커지는 경우의 수가 존재한다.
(실제로 이런 수가 나오진 않겠지만)

따라서 double을 사용하는 것이 맞다.

double은 정밀도가 15자리이기 때문에 (A와 B가 0초과 10미만의 정수라, 나눗셈 결과의 정수 부분이 최대 1자리이다) 오차가 10^(-9)보다 무조건 작다.

추가적으로

cout.precision(10);
cout << fixed;

를 통해 소수점 아래 10번째 자리까지 표현하도록하여 오차를 10^(-9)보다 무조건 작게 설정한다.

(2) <stdio.h>

#include <stdio.h>

int main() {
    
    double a,b;
    scanf("%lf %lf", &a, &b);
    printf("%.10lf", a/b);
    
    
    return 0;
}

마찬가지로 double을 사용했고 형식 지정자는 %.10lf 로 하여 소수점 아래 10번째 자리까지 출력하도록 (소수점 아래 11번째 자리에서 반올림) 설정했다.

(3) <cstdio>

#include <cstdio>
using namespace std;

int main() {
    
    double a,b;
    scanf("%lf %lf", &a, &b);
    printf("%.10lf", a/b);
    
    
    return 0;
}

<stdio.h>를 사용했을 때와 동일하다.

profile
안녕하세요. 전자공학부 학부생의 공부 기록입니다.

0개의 댓글