• 카테고리

    질문 & 답변
  • 세부 분야

    프로그래밍 언어

  • 해결 여부

    미해결

float 형 데이터가 메모리에 저장될때

22.08.22 14:22 작성 조회수 234

0

- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요!
- 먼저 유사한 질문이 있었는지 검색해보세요.
- 서로 예의를 지키며 존중하는 문화를 만들어가요.
- 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요.
 
첫번째 질문
float 형 데이터가 메모리에 저장될때 이진수를
정규화(?)시켜서 저장이 된다고 하는데(구글링했습니다)
쉽게 말하면 부동소수점수와 근사하는 이진수데이터를 메모리에 저장한다는 뜻인가요?
set precision(17)로 float d=0.1 를 출력하면
강의에서와 같이 마지막소수점이 1로 나왔다는건
메모리에 저장되어있는수가 실제 0.1이 아닌 소수점 18번째 자리부터 반올림했을때 올라가는 0.1에 근사한수 인지입니다.
 
두번째 질문
구글링해보니 setprecision 은 정수부,소수부를 포함하여
고정된 n 의 너비를 가지게끔 입출력을 조작하는 함수라고 나와있습니다.
그런데 0.1 과 3.14159 를 비교하여 출력해보니 너비가 다르게 나옵니다.
정수부나 소수부가 0인경우 너비를 고려하지 않는건가요?
 
세번째 질문
double d = 0.1 을 선언하고나면 메모리에 0.1 에 근사하게끔 0과1로 메모리가 저장된다고 한다면
setprecision 을 적지않고 d 를 출력했을때 왜 0.1 이 출력되는건가요?
메모리에 저장되어있는 수를 꺼내는 원리가 아니라
내가 초기화시킨 값의 형식(적은 수의 모양 자체) 를 출력해주는 건가요?
 

답변 1

답변을 작성해보세요.

0

강민철님의 프로필

강민철

2022.08.23

안녕하세요, 하나씩 답변드리겠습니다.

 

첫번째 질문

진수부와 가수부를 나누어 저장하고자 하는 값에 맞춰 저장하는 것입니다.

굳이 근사화시키지 않고도 0.1을 표현할 수 있다면 근사시키지 않고 해당 값 자체를

이진수화한 값을 메모리에 저장합니다.

(혹시 소수의 저장 방식에 대해 모호하시다면 세 번째 질문에 대한 답변을 참고해주세요)

 

두 번째 질문

혹시 아래와 같이 작성하셨나요? 그렇다는 전제 하에 답변드립니다.

#include <iostream>  
#include <iomanip>      // std::setprecision

int main () {
  double f = 1.1;
  double f2 = 3.14159;
  std::cout << std::setprecision(5) << f << ' ' << f2 << '\n';
  std::cout << std::setprecision(9) << f << ' ' << f2 << '\n';
  return 0;

}

 

0일 경우라서 그렇다기 보다는 자릿수가 fixed하지 않아서 그럴 것입니다.

위 코드의 경우에도 정수부가 1인데도 출력하면 f는 1.1로 출력될 것입니다.

 

아래와 같이 std::fixed;로 고정하고 출력해보시면 원하는 결과를 얻을 수 있을 것입니다.

 

#include <iostream>     // std::cout, std::fixed
#include <iomanip>      // std::setprecision

int main () {
  double f = 1.1;
  double f2 = 3.14159;
  std::cout << std::fixed;

  std::cout << std::setprecision(5) << f << ' ' << f2 << '\n';
  std::cout << std::setprecision(9) << f << ' ' << f2 << '\n';
  return 0;

}

 

혹시 궁금하실까봐 std::fixed 관련 문서도 첨부해드립니다.

https://cplusplus.com/reference/ios/fixed/

 

세번째 질문

음.. 이 부분은 (setprecision과 무관하게)

소수가 메모리에 저장되는 방식에 대해 이해하시는 것이 좋을 것 같습니다.

이 문서를 참고해보세요.

 

 

 

차경원님의 프로필

차경원

질문자

2022.08.24

보내주신 링크의 글 감사히 읽었습니다.

십진수로 부동소수점표현시킨 수를 이진수의 부동소수점표현으로 바꾼다음

지수부분에 음수까지 고려하기때문에 음수까지 표현하게끔 구간을 0이 중앙이되게끔 이동시킨다

였네요. 다만 소수점의 이진수표현이라던가, 이진수를 2의n승으로 묶는 방식은 처음 접해봐서 생소하지만 float 형이 어떤원리로 이진수로 저장되는지는 이해가 됩니다. 감사합니다.

읽고나니 생각보다 궁금한게 많이 생기네요.

질문거리가 많은데 정말 죄송하지만 한번만 부탁드립니다 ㅠ

====================================================================

(1) 0.1 이 정확하게 float (유한)으로 표현이 된다면 왜 precision 을 16으로 설정하면

0.1이 출력되지만 17로 설정하면 강의에서처럼 0.100...01 이 출력됩니다.

그래서 0.1 의 precision 을 100 이랑 101 로 늘려서 출력해봤는데

이렇게 출력이 되네요

그래서 드리는 질문이 

1. 모든 10진수 float 이 진수부와 가수부로 표현이 안되는건가요? 

2. 안된다면 그이유가 2진수의 float 으로 바꿨을때 무한소수가 되버려서인가요?

(0.1 을 2진수 float 으로 바꾸려했는데 소수가 무한개 생기는것 같더군요. 그래서 2진수일때 유한소수가되는 0.625 를 

precision 을 1000으로 두고 출력해봤는데 오차없이 0.625로 출력되서 질문 드립니다.)

3. precision 을 100과 101로 했을때 출력되는 값이 같음을 미루어 보았을때 실제로 메모리에 저장되는 값은 사진에 나와있는 수인것 같은데 그 이유가 2진수float 변형시 무한소수가 되버려서 메모리에 전부 들어가지 못하고 메모리에 저장된 수만 표현이 된게 사진에 나와있는 수인건가요?

 

4. 실제로 메모리에 저장되있는 수는 사진에 나와있는 수인것 같은데 

왜 precision 을 안쓰고 출력하면 0.1만 출력되는건가요?

(사실 질문들이 모두  전 질문이 참이어야 물어봐야되는건데  한번에 답을 듣고싶어서 우르르 질문했씁니다. 죄송합니다)

 

 

 

두번째 질문에서 code를 이렇게 짰었는데

얼핏 보면 d1 은 정수부가 0이라 너비를 소수부에서만 센거고 d2 는 그게 아니기 때문에 정수부까지 포함해서 너비를 세서 마지막 소수자리가 반올림되서 들어간것 같아 보여서 질문 드렸습니다. 주신 링크는 봐봤지만 모르는 용어들이 많아서 잘 이해하기가 힘드네요 ㅠ

 

# 이해도 못하고, 너무 많이 질문해서 죄송합니다 ㅠㅠ

강민철님의 프로필

강민철

2022.08.24

음.. 뭔가 이해를 하시는 초반부 (1번 질문)부터 꼬이신 것 같은데,

말씀하신대로 질문이 꼬리에 꼬리를 무는 형태(앞선 질문이 참이라는 전제 하에 추가적인 질문을 해주신 형태)라서 

모든 질문에 대해 답변해드리기보다는 우선 제 나름대로 답변드리겠습니다. 

1. 10진수로 표현된 float 형도 내부적으로 진수부와 가수부로 저장됩니다.

2. 네. 십진수로 표현된 소수라 할지라도 내부적으로 저장될 때에는 이진수로 저장되는데, 이게 딱 떨어지게 변환되지 않을 때가 많습니다. 가령 아래 링크에 0.1을 입력해보세요. 

0000.0001100110011001101 이런 식으로 나올 것입니다.

https://www.binaryhexconverter.com/decimal-to-binary-converter

3. 네 맞습니다.

4. 이건 앞선 답변에서 말씀드렸듯 소수가 실제로 메모리에 저장되는 방식과는 무관하게 출력을 하는 과정에서 std::fixed를 하지 않았기 때문으로 보입니다. fixed 하지 않고 출력한다면 가령 그냥 단순히 0.1 을 출력한다고 했을 때 이를 이진수로 표현한 값을 무조건 전부 일일이 출력하는 것이 아닌 (혹은 100 자리까지 출력하라, 101 자리까지 출력하라에 맞게 출력되는 것이 아닌) 그냥 첫 번째 자리만으로 출력되는 것입니다.

 

차경원님의 프로필

차경원

질문자

2022.08.24

fixed 를 하지 않았기 때문에 첫번째 자리만 출력이 된다고 하셨는데, 

0.011 도 마찬가지로 메모리에 저장된값과 오차가 생기지만 fixed 하지 않고 출력할 경우 0.011 이 출력됩니다. 

그러면 0.1 , 0.011 모두 메모리에는 오차가나게 저장이되고 변수를 초기화할때 소수점자리도 서로 다릅니다. 그런데 컴파일러는 정확하게 0.1 과 0.011 을 출력시켜줍니다.

0.1 이 0.100으로 출력될수도 0.011이 0.01로 출력될수도있는데 마치 사용자의 의도를 파악한것처럼 초기화시킨값 그대로 출력해주는게 이해가 잘안됩니다.

강민철님의 프로필

강민철

2022.08.24

음 말씀하신 오차는 십진수로 변환했을 때 소수 둘째자리, 첫째자리까지 차이가 날 만큼 그 차이가 크질 않습니다.

그래서 첫째자리나 두세자리 정도 출력할 때에는 크게 오차가 나질 않는 것입니다.

(물론 100째자리 정도로 출력하면 차이가 나겠지만요..)

 

추가로, 소수가 저장될 적에 생기는 오차는 분명 존재하지만 그 오차는 소수 N(N은 충분히 큰 수)에서만 발생하는 예외적인 상황인 경우가 많습니다.

지금으로서는 그러한 오차가 내부적으로 존재할 수 있다는 점만 인지하시고 넘어가셔도 문제 없으니 우선 학습을 나아가시길 권합니다 :)

차경원님의 프로필

차경원

질문자

2022.08.24

넹 질문 감사합니다