소수 표현시 유효자리에 대한 궁금증이 있습니다.

yann8166의 이미지

C와 C++에서 float형의 유효숫자 자리가 7자리라고 하는데

어떤 분께서는 정확히는 6자리라고 하시더군요.

무튼.. 6자리라고 가정하고 입력된 값을 "%.10f"로 소수 이하 10자리까지 표현한다고 할때

입력 : 123.99
출력 : 123.9899978638

입력 : 0.9999
출력 : 0.9998999834

이렇게 나옵니다.

첫 입력의 경우 지수+가수 하여서 5자리 이고

두번재 경우도 소수 4번째 자리까지만 입력 하였는데

어째서 6자리의 유효숫자가 오차가 발생하는 걸까요??

snowall의 이미지

0.도 유효숫자로 쳐야 하지 않나요?

피할 수 있을때 즐겨라! http://melotopia.net/b

ifree의 이미지

일단 입력하신 두 소수가 이진수로는 무한소수입니다.
즉, 입력 자체가 정확하게 안되는 거죠.
유한 소수로 다시 해보세요.

chanik의 이미지

참고자료 : http://en.wikipedia.org/wiki/Binary32

123.99를 이진수로 변환하면 아래와 같은 결과가 나옵니다.
무한소수입니다. scale을 100 이상으로 아무리 크게 늘려도 끝나지 않습니다.

$ echo "scale=100; ibase=10; obase=2; 12399 * 10^-2" |bc
1111011.111111010111000010100011110101110000101000111101011100001010\
00111101011100001010001111010111000010100011110101110000101000111101\
01110000101000111101011100001010001111010111000010100011110101110000\
10100011110101110000101000111101011100001010001111010111000010100011\
11010111000010100011110101110000101000111101011100001010001111010111\
0

참고로 16진수로 변환하면 아래와 같은데, 이진수에서는 알아보기 어려웠던 패턴이 보입니다.
소수점 아래 두번째 자리부터 D70A3이 반복되는 순환소수임을 알 수 있죠.

$ echo "scale=100; ibase=10; obase=16; 12399 * 10^-2" |bc
7B.FD70A3D70A3D70A3D70A3D70A3D70A3D70A3D70A3D70A3D70A3D70A3D70A3D70A\
3D70A3D70A3D70A3D70

즉, 십진수로는 딱 떨어지던 123.99가 2진수/16진수로 변환하게 되면 순환소수인 무한소수가 됩니다.
이것을 32-bit float 타입에 저장하려면 가수부는 총 23bit까지만 저장 가능하므로
위의 무한소수가운데 1111011.11111101011100001 까지의 유효숫자만 보존되고,
2^6 * 1.11101111111101011100001 형태로 소숫점 자리가 이동되어 각각 지수부와 가수부에 저장됩니다.

주의할 점은, 가수부에 저장되는 것은 빨간색으로 표시된 23비트뿐이고
녹색으로 표시된 1비트는 실제로 저장되지는 않지만 항상 가수부에 1.0을 더하는 규칙의 형태로 존재한다는 것입니다.
사실상 24개의 유효숫자를 23자리에 표기한다고 생각하면 되겠습니다.

이런 식으로 유효숫자가 잘려나간 채로 float에 저장되므로
이후 printf에서 다시 10진수로 변환하면 처음의 123.99와는 다른 결과가 나오게 되는 것입니다.

2^6 * 1.11101111111101011100001
=> 1111011.11111101011100001
=> 123.98999786376953125

2진수에서 10진수로의 변환은 아래와 같이 확인해볼수 있습니다.

$ echo "ibase=2; obase=A; 1111011.11111101011100001" |bc
123.98999786376953125
jick의 이미지

2진수 설명은 위의 chanik 님이 잘 해주셨고,

123.9899978638 를 여섯자리만 남기고 반올림하면 123.990입니다. 처음 준 숫자를 유효숫자 여섯자리까지 정확히 맞췄는데 왜 오차가 난다고 생각하시는지요.

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.