[완료] 컴퓨터에서는 0.1을 어떻게 저장/표현 하나요?!

맨발의 이미지

1. 컴퓨터에서는 모든 데이타를 2진수로 저장
2. 0.1을 이진수로 표현 하면 0.0011001100110011001100..............
3. 단정밀도(single precision)에서는 23자리의 이진수만 저장

이럴때 0.1 + 0.1 이런 계산은 단정밀도에서 오류가 있게 나온다 쳐도
0.1 자체는 저장하고 불러내도 별 이상 없잖아요?

컴퓨터에서는 0.1을 어떻게 저장 하고 있는건가요?
(문자열로 저장하나? ㅡㅡ;;)

(답변 다신 분 중에 좀 더 구체적인 질문을 요청 한 분이 계셔서 글을 더 첨부 합니다.)
조금 더 단순하게 말하면,
0.1이나 0.3은 32비트 single precision로 표현이 불가능 한데..
어떻게 컴퓨터에서 사용 되느냐 입니다.

예를 들어보면, 다음은 32bit 리눅스 머신에서 GCC로 컴파일일 했는데..
(gcc version 3.4.6 20060404 (Red Hat 3.4.6-11)

#include

int main()
{
float f = 0.3;
printf("%f", f);
return 0;
}

결과는
0.300000
입니다.

float f = 0.3; 에서 0.3이 32bit 의 메모리 공간에 저장 되었다가
printf 할 때 메모리에서 불려와서 화면에 출력 되는데..

IEE754 규격으로는 이진수로 변경 했다가 십진수로 변경 할 때 값의 차이가 있는데도
어떻게 제 값으로 출력 가능한지 원리가 궁금한거예요.

mithrandir의 이미지

쓰신게 맞습니다.

http://en.wikipedia.org/wiki/IEEE_754-2008
23자리(23bit)는 single precision, 32bit형에 해당하겠네요.

물론 구현에 따라 다른 방법으로 표현할 수도 있겠지만, cpu가 지원하는 기본연산이 대부분 저것(IEEE754)을 기준으로 만들어지니까
저것을 사용하게 됩니다.

언제나 삽질 - http://tisphie.net/typo/
프로그래밍 언어 개발 - http://langdev.net

언제나 삽질 - http://tisphie.net/typo/
프로그래밍 언어 개발 - http://langdev.net

맨발의 이미지

아니.. 제가 궁금한건.. 0.1이 이진수로 변경 안되는데
어떻게 메모리에 올리고 하드에 저장하느냐 입니다.
(문자열로 저장 한다는 말이 맞다는 말은 아니지요?)

--------------------------------------------
:: 누구보다 빠르게 남들과는 다르게

mithrandir의 이미지

이진수로 표현이 안된다는게 맞습니다.

즉 0.1로 저장이 안됩니다.
0.1에 근사한 이진수 값으로 표현되죠.

일반적으로 우리가 쓰는 x86등의 환경에서는요.

언제나 삽질 - http://tisphie.net/typo/
프로그래밍 언어 개발 - http://langdev.net

언제나 삽질 - http://tisphie.net/typo/
프로그래밍 언어 개발 - http://langdev.net

vacancy의 이미지


10진수로 저장하는 경우도 있습니다.
( IBM POWER6 architecture에서는 하드웨어 수준에서 지원합니다. )

Decimal floating-point 로 검색해보세요.

맨발의 이미지

그럼 저장할때는 float형도 decimal형으로 저장 된다는 말씀?!
하드웨어 수준에서 처리 하는 특이한 경우(?)말고
일반적인 PC에서의 상황이 더 궁금하네요..

--------------------------------------------
:: 누구보다 빠르게 남들과는 다르게

ifree의 이미지

0.1 = 1 x e-1 의 형태로 저장됩니다.
즉, 유효숫자 1, 소수점 위치 -1 이 각각 저장되죠.

맨발의 이미지

말씀하신 데로면
0.1 * 10 * e-1 인데..

그렇다면 1.3 이라면
1.3 * 10 * e-1 즉,
1011 x e-1 이렇게 되나요?

가수부는 2진수로 표현하고 지수부는 10진수?

이건 아닌것 같은데요..
(참고로 0.3도 이진수로 변환 하면 0100110011001... 1001이 무한 반복 입니다.)

--------------------------------------------
:: 누구보다 빠르게 남들과는 다르게

ifree의 이미지

가수부건 지수부건 2진수로 저장되죠.
정확하게는 single precision(32비트)에서는 부호 1비트, 지수부 8비트, 가수부 23비트를 사용하므로 유효숫자는 최대 7개까지 가능합니다.

기본적인 것은 먼저 검색을 좀,

맨발의 이미지

음.. 아무리 봐도
0.1 은 1 x e-1 이라는 예제는 e-1이 십진수로 밖에 이해가 안됩니다.
(제가 이해력이 딸리나 보군요.. 죄송해요..)

1.3을 예로 들어서 설명해 주시면 이해가 될듯 해요.

그리고 23자리에서 짤리다.. 라는 답변을 원하는게 아니고
그걸 다시 10진수로 바꿀때 컴퓨터에서 어떻게 하기에 1.3으로 돌아오는지 알고 싶은거구요..

밑에분 글에 C소스를 첨부로 좀 더 구체적인 예를 달았습니다.

--------------------------------------------
:: 누구보다 빠르게 남들과는 다르게

ifree의 이미지

e-1 이 아니고 -1 이 지수부에 저장되게 되죠.

예들 들어 56.327 라는 실수가 있으면,
가수부에 56327, 지수부에 2 값이 들어갑니다.

creativeidler의 이미지

floating point로 구글링해보세요.

맨발의 이미지

검색을 해봐도 문제점 밖에 못찾겠네요..
제가 궁금한건 어떻게 그 문제를 해결 했나 인데..
(아래분 답변에 질문을 좀 더 구체적으로 올렸어요.)

저의 한계.. ㅠㅠ

--------------------------------------------
:: 누구보다 빠르게 남들과는 다르게

creativeidler의 이미지

검색 결과에서 첫번째로 나오는 위키피디아의 문서를 처음부터 끝까지 읽어보세요. 그러면 자연스럽게 이해가 될 겁니다.

0.3이 컴퓨터에 저장될 때 0.3을 수학적으로 이진수로 변환한 값이 저장되는 것이 아니고, floating point 저장을 위한 포맷이 따로 있고, 그 포맷에 따라 각 비트의 값이 결정됩니다. 그게 위에도 나왔던 IEEE 754이고, 그 포맷만 이해하면 어떻게 0.3을 메모리에 저장하고 다시 불러올 때 왜 정확한 값이 나올 수 있는지 알 수 있습니다. floating point는 유효 자리수 이내에서는 늘 정확한 값을 가져옵니다. 15자리씩 찍었을 때 값이 이상한 것은 유효 자리수를 넘었기 때문이고, 유효 자리수 이내의 숫자들은 늘 정확하게 찍힙니다.

xylosper의 이미지

"0.1 자체는 저장하고 불러내도 별 이상 없잖아요?"

"저장하고 불러내기"가 무엇인지, 그리고 "별 이상이 없다"는 것은 무엇을 의미하는지를 명확히해주세요.
기왕이면 별이상없이 저장하고 불러내는 코드가 있으면 더 좋구요.
단순히 0.1을 최대유효자리수까지 출력해보기만 해도 0.1이 출력되진 않습니다.

맨발의 이미지

조금더 단순하게 말하면
0.1이나 0.3은 32비트 single precision로 표현이 불가능 한데..
어떻게 컴퓨터에서 사용 되느냐 입니다.

예를 들어보면, 다음은 32bit 리눅스 머신에서 GCC로 컴파일일 했는데..
(gcc version 3.4.6 20060404 (Red Hat 3.4.6-11)

#include

int main()
{
float f = 0.3;
printf("%f", f);
return 0;
}

결과는
0.300000
입니다.

float f = 0.3; 에서 0.3이 32bit 의 메모리 공간에 저장 되었다가
printf 할 때 메모리에서 불려와서 화면에 출력 되는데..

이진수로 변경 했다가 십진수로 변경 할 때 값의 차이가 있는데도
어떻게 제 값으로 출력 가능한지 원리가 궁금한거예요.

--------------------------------------------
:: 누구보다 빠르게 남들과는 다르게

dg의 이미지

소수점 이하 20자리까지 출력해 보았습니다.

#include <stdio.h>
 
int main(void)
{
    float f = 0.3;
    printf("%.20f\n", f);
    return 0;
}

결과

0.30000001192092895508

gcc 4.4.3, x86_64

kimback100의 이미지

완전 생초보

컴퓨터에 문제가 많은데여. 하다못해 인턴넷도 정보의 바다가 정보의 쓰레기장이 된지가 오래잖아여.?

거기다 이제는 모바일가지 가세해서 하루도 핸폰없이는 못살겠다는 인간들이 수두룩한데 그게다 그 시초

는 디지털이잖아여. 하나에서 열까지 모두 가르쳐주어야만 해내는 디지털. 이런 식이라면 저는 별로 현대

문명의 이기들이 반갑지가 않타고 생각이 드는구녕. 그럼 안녕히.....

ps.엑셀에서는 저런 경우 숫하게 많치않나여. 함수 조금만 하면 금새 맞닥뜨릴법한 상황인데 말입니다.
문제도많코 거기다가 어렵기까지 한 이놈의 디지털 고철덩어리들대체할 수 있는 피조물은 오로지 신밖에
없는듯합니다. 오신이시여.... 저를 빨리 당신의 천국으로 이끌어주소서 아멘~~~~~~~

완전 생초보

맨발의 이미지

.

--------------------------------------------
:: 누구보다 빠르게 남들과는 다르게

맨발의 이미지

앗.. 어느 커뮤니티에나 꼭 한 분씩은 있다는 그 분? ㅋ

--------------------------------------------
:: 누구보다 빠르게 남들과는 다르게

octaphial의 이미지

앞의 여러 분들이 답해드린 좋은 답을 좀 읽어보시지 않구요...

[octaphial@octaphial-laptop test]$ vi float.c
#include <stdio.h>
 
int main () {
        float f = 0.3;
 
        printf ("%.15f\n", f);
 
        return 0;
}
[octaphial@octaphial-laptop test]$ gcc -o float float.c
[octaphial@octaphial-laptop test]$ ./float
0.300000011920929
[octaphial@octaphial-laptop test]$ 

사족으로 본인이 쓰신 코드에서 숫자가 좋게 보이는 그 기법을 보통 반올림, 올림, 버림이라고 하지요...

맨발의 이미지

이 글이 제가 원한 글이네요.
결국 제가 소숫점 저~ 밑에 까지 보질 않아서
오류있게 출력을 되는거 바르게 출력 된다고 착각하고 있었던 것 이군요.
감사합니다.

헌데..
"앞의 여러 분들이 답해드린 좋은 답을 좀 읽어보시지 않구요..."
이런글 읽으면 꼭 검색도 안하고 글 쓴 바보 된 기분이네요.
흑..

--------------------------------------------
:: 누구보다 빠르게 남들과는 다르게

pastime의 이미지

참고로.. C99에서 제공하는 %a 변환 지정자를 이용하면
printf()를 통해 지수부와 가수부에 저장된 값을 16진수로 볼 수 있습니다.

$ cat show_fp.c 
#include <stdio.h>
 
int main (void)
{
  printf("%a\n", 0.3);
  return 0;
}
$
$ gcc show_fp.c
$ ./a.out
0x1.3333333333333p-2
맨발의 이미지

감사합니다.

--------------------------------------------
:: 누구보다 빠르게 남들과는 다르게

vivisection의 이미지

float f = 0.0;
int i = 0;

while(i<100) { // 100번 반복...
f += 0.1;
i++;
}

printf("%f\n", f);

예전엔 이러게하면 9.9가 출력됬는데 요샌 10 이 출력되더군요..

32비트일때..

그러면 2진수로 32자리란 건.. 뭐 아실테고.

첫번째가 부호비트, 1이면 음수 0이면 양수

그다음 몇비트가 가수, 그다음부터 몇비트가 지수 부분인지는 약속되있는거고(저도 기억이 잘..)

그상태로 그냥 메모리에 떠있는거죠..

메모리의 주소는 포인터나 변수이름이 가지고있습죠

근데 질문에 안맞는 답변같네요.. 죄송

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.