float type 관련하여 문의 드립니다.

fctjsh의 이미지

아래 문제가 있습니다.
결과는 1000이 나와야 하지만 그렇지 않고 999.xxx 이런식으로 나옵니다.

float을 공부해본 결과 부동소수점 어쩌고 해서....유효자리수가 소수점 이하 7자리 정도 된다고 하네요.
그럼 당연히 0.1 x 10000은 소소점 이하 7자리가 안되니 계산이 잘되어 나와야 할 것 같은데 여전히 제대로 나오지 않네요.

왜 그런거죠?? 고수님들 자세한 답변 부탁 드릴께요.

벌써 3일째 이러고 있어요....

#include

void main()
{
float f = 0.1;
float sum = 0.0;
int i;

for( i=0; i<10000; i++ )
sum += f;

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

bushi의 이미지

gilgil의 이미지

float의 정확한 원리를 알고 있어야 이러한 상태의 발생을 막을 수 있습니다.

NEIS 사태에 대한 기술적인 설명 : http://www.gilgil.net/8358

fctjsh의 이미지

float 이랑 double 을 사용하지 말아야 겠다는 생각밖에 안드네요.
결국 100% 안전한 벙법은 없다는 것 같아 보여서...

float을 가지고 안전하게 설계 하려면 어떻게 해야 하는지에 대한 가이드 자료 같은건 없나요?

qiiiiiiiip의 이미지

floating point 세계에서 a == b 라는 연산을 하면 안되는거죠.
이것만 안하면 ( explicitly/implicitly ) 충분히 "안전" 합니다.

ifree의 이미지

1000 이전에 유효숫자가 10진수로 서너자리인 수가 나오고, 이들이 연산되면서 부정확해지는 듯 합니다.
가능하면 double 을 사용하시고, 실수 연산 결과에 대한 tolerance 를 미리 염두에 두는 것이 좋을 것입니다.

3D 렌더링이나 인코딩 프로그램 중에 GPU 연산을 지원하는 프로그램들이 있습니다.
CPU 연산은 배정밀도이고, 일반적으로 GPU 연산은 단정밀도인데,
일부 인코딩 프로그램에서 단정밀도를 사용한 결과가 상당히 안좋다는 말을 들은 적이 있습니다.
렌더링인 경우는, Luxrender 라는 렌더러를 배정밀도와 단정밀도로 모두 돌려 보았는데, 결과물의 차이를 눈으로 확인하기는 불가능했습니다.

qiiiiiiiip의 이미지

10진수로 0.1자체가 2진수로 표현하기 어려운 수입니다.
double로도 마찬가지이고요.

$ cat a.c
#include <stdio.h>
int main()
{
    printf( "%80.79f\n", 0.1f );
    printf( "%80.79f\n", 0.1 );
    return 0;
}

$ gcc a.c
$ ./a.out
0.1000000014901161193847656250000000000000000000000000000000000000000000000000000
0.1000000000000000055511151231257827021181583404541015625000000000000000000000000

0.1 == 0.1 이 false 라고 고민해야할 프로그램이라면 float를 쓰면 안되죠.

ifree의 이미지

표현하기 어렵다기 보다는 0.1 이 이진수로는 무한 소수이기 때문에 정확히 표현할 수 없다고 해야겠죠.
0.5는 이진수로 한자리로 간단히 표현되기 때문에, 본문의 연산을 하면 정확한 결과가 나옵니다.

float, double 의 경우에도 등호나 부등호 연산이 필요한 경우가 있습니다.
이 경우는 경우마다 별도로 허용값을 정해 등호 연산을 정의해야 합니다.

DarkSide의 이미지

이런! 0.1이 이진수로 무한 소수였구나...
이 문제에서는 이게 근원적 문제였군요.

fctjsh의 이미지

#include 

void main()
{
    int i;
    float a = 0.1f;
    float sum = 0;

    for(i = 0; i 

0.100000001490116120000000000000
0.200000002980232240000000000000
0.300000011920928960000000000000

이렇게 한번 돌려 봤는데...
0.1 = 0.100000001490116120000000000000
0.2 = 0.100000001490116120000000000000 + 0.100000001490116120000000000000
0.3 != 0.100000001490116120000000000000 + 0.100000001490116120000000000000 + 0.100000001490116120000000000000

0.3은 0.1을 세번 더한 값이 아니네요...
visual studio 에서 돌렸는데 0.3 부터는 다르게 더하나봐요..

이거 정말 징하게 어렵네요...

DarkSide의 이미지

윗분들이 이유를 다 말해 주셨는데 좀 보세요.
0.1, 0.2, 0.3, 0.4 등은 이진수로는 무한소수이기 때문에 이런 수를 가지고 계산하면 유효 숫자로 뒤가 짤려서 덧셈이 부정확해지는 거고,
0.5, 0.25 등은 이진수로 간단한 유한 소수이기 때문에 정확한 결과가 나옵니다.
계산을 다르게 더하는게 아니에요.

fctjsh의 이미지

내부 비트 연산이 어떻게 되는지 궁금해서 올린 글인데
질문을 잘못된 방법으로 했네요...죄송합니다.

0.1
0 01111011 1001100110011001100110

0.2
0 01111100 1001100110011001100110

0.3
0 01111101 0011001100110011001101

실제 float은 내부적으로 위와 같은 4바이트로 저장 되는데...
당연 컴터니 비트 연산을 할 것 같고..

0.1과 0.2 가 어떻게 더해져 0.3 이 나오는지 궁금해서요..

무지해서 죄송..ㅜㅜ

gilgil의 이미지

실수의 체계는 정수의 체계와는 다릅니다. 일반적으로 실수는 s(sign), e(exponent), f(fraction) 부분으로 나뉩니다.

http://en.wikipedia.org/wiki/Single_precision_floating-point_format

즉 s, f, e가 주어 질 때 실수의 값은 수학 공식으로 써 보자면 다음과 같습니다.

value = 2 ^ e * f (s가 0이면 양수, 1이면 음수)

덧셈의 경우에는 2개의 숫자의 exponent를 먼저 맞춘 다음 fraction 부분을 더하게 되겠죠.

실수(float)의 sign, exponent, fraction을 출력해 주는 프로그램을 작성한 것이 있으니 참고하시기 바랍니다.

http://www.gilgil.net/11340

fctjsh의 이미지

위의 숫자들은 실수 float을 union을 사용하여 출력해주는 프로그램을 통하여 이미 출력된 내용이에요.

제가 궁금한건 아래 말씀 하신 이 내용의 과정을 보고 싶어서요....

"덧셈의 경우에는 2개의 숫자의 exponent를 먼저 맞춘 다음 fraction 부분을 더하게 되겠죠."

gilgil의 이미지

구글링해 보니 금방 나오네요.

http://www.cs.umd.edu/class/sum2003/cmsc311/Notes/BinMath/addFloat.html

요즘 컴퓨터 환경에서는 위 URL에서 표현된 실수 연산 계산 방식을 CPU 혹은 co-processor에서 처리해 주고 있기 때문에 SW 프로그래머가 꼭 알아야 할 필요는 없다고 봅니다.

DarkSide의 이미지

0.1(DEC) = 0.00011001100110011...(BIN)
0.2(DEC) = 0.00110011001100110...(BIN)
+_____________________________________
0.3(DEC) = 0.010011001100110.....(BIN)

fctjsh의 이미지

꾸벅..

댓글 달기

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