gcc가 자신이 돌았다고 고백했습니다.

seoleda의 이미지

double sum;
sum = 0.3+0.6+0.1;
//sum = 0.3f+0.6f+0.1f;
printf("%f\n", sum);
if (sum==1.0){
    printf("I am smart!!\n");
}else{
    printf("what!!, am I creazy?");
}

gcc가 자신이 돌았다고 고백했습니다.
sum을 float로 하면 결과가 제데로 나오긴 하지만, 위와 같은 코드는 예상한대로 동작하지 않더군요.
gcc 버젼이 3.3.5-13 인데, gcc 버그인가요?

방금 ubuntu/breezy (gcc 4.0.2) 에서도 자신이 돌았다는 고백을 받았습니다. 어찌해야 하나요?
점점더 해깔려집니다. 내가 돌은건지 컴퓨터가 돌은건지..
혹시 몰래 카메라가 아닐까 의심도 듭니다. TT

dopesoul의 이미지

asm 으로 컴파일 된 것을 봐야할것 같네요.^^;

Anonymousㅁ의 이미지

플로팅포인트 변수의 == 비교는 좋지 않습니다.
fraction을 위한 비트가 한정되어 있기 때문에... 어쨋든 모든 실수를 정확하게 표현할 수가 없죠. 0.1의 경우에도 1/2 + 1/2^2 + 1/2^3 ...으로만 표현되지 정확하게 나타낼 수가 없으니까요.

bugiii의 이미지

컴퓨터가 실수를 표현하는 방법상의 오차 문제입니다. 실수의 값 비교는 등호로 하지 않는 것이 문제를 피해가는 방법입니다. (그렇게 하면 안되는 것입니다.) 오차범위를 검사하여 그 범위에 들면 맞다고 판단하는 것이 맞습니다. 그 오차범위는 실수값의 정밀도나 연산의 결과에 따른 것으로 하는 것이 일반적입니다.

여기 게시판에도 몇번 언급된 문제이므로, 검색을 해보시면 여러가지 의견이 있을 것입니다.

cinsk의 이미지

GCC가 잘못된 것이 아니라, 컴퓨터에서 floating point(실수)를 표현하는 방식때문에 그렇습니다. 사실 정확한 실수를 표현하기 위해 특별한 실수 처리 라이브러리를 쓰지 않는한 모든 실수를 다 표현하는 것은 불가능합니다.

간단히 예로 들어 2진수 기반에서 십진수 0.1도 제대로 표현할 수 없습니다. (이진수 0.0001100110011...로 표현됨).

printf(3)가 보통 이런 수치를 만나면 반올림해서 보여주기 때문에, 실제 표현 값과 다르게 보일 수 있습니다. 즉 sum이 1로 출력되더라도 사실 1이 아닌 0.99999... 일 가능성이 있습니다. 따라서 sum == 1.0이 실패할 수도 있습니다. 두 실수를 비교할 때, 이런 식으로 하는 것은 오차가 있을 수 있기 때문에 적당한 방법이 아닙니다. 차라리 다음과 같이 어느 정도 오차를 인정하는 선에서 코드를 작성해야 합니다. 만약 두 실수 a, b를 비교한다면,

if (a == b)
    ...

를 쓰는 것은 나쁜 방법이며,

#include <math.h>
#include <float.h>
 
if (fabs(a - b) <= EPSILON * fabs(a))
    ...

로 쓰는 것이 좋습니다. 이 때 EPSILON은 data type이 float, double, long double일 때, 각각 FLT_EPSILON, DBL_EPSILON, LDBL_EPSION을 쓰는 것이 좋습니다.

epsilon의 정확한 의미나 더 자세한 것은 수학을 잘 하시는 분들이 해 주실 겁니다. 전 수학에 약해서... :(

--
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
Korean Ver: http://www.cinsk.org/cfaqs/

seoleda의 이미지

옆사람에게 물어 봤더니, 왜 그런지는 잘 모르지만  if (a-b <=0) {...} 로 하라고 하더군요. b가 음수면 어쩔거냐고 물었더니 모른다네요. ^^
cinsk님의 방법은 음수일 경우에도 문제가 없을듯 합니다. 감사합니다.

지금 생각해 보니, 소수부가 2^- n 의 합으로 표시되지 않는 경우, 오차가 생긴다는 사실을 수업시간에 들을땐, "나랑 별 상관없는 이야기군" 넘어갔는데 알고보니 상관이 아주 많은 이야기 였네요.

p.s. 좀 다른 이야기지만, C/C++ 의 표준에서 실수형 == 연산을 cinsk 님의 방법과 같이 정의하지 않는 이유는 무었인가요? 혹시 저같이 순진한 사람들을 놀리려는 의도인지... ^^

ㄹㄹㄹ의 이미지

어쨌거나 틀린 거를 맞다고 할 수는 없는 일이지요. 수치 연산을 대단히 많이 하는 프로그램인 경우 이런 오차도 신경을 써줘야 합니다. 오차에 오차가 겹쳐 엉뚱한 결과가 나올 수도 있지요. 이런 경우 가능한한 오차를 줄일 수 있는 계산식을 사용하거나, 속도가 문제되지 않는다면 무한 정밀도 라이브러리를 사용해야 합니다. 그런데 컴파일러 차원에서 그냥 부동소수점 오차를 무시해버리면 이게 오차가 얼마나 생기는 건지, 맞는 건지 틀린건지를 판단하기가 어렵지요. 그냥 한계를 인정한 정직한 정의라고 보시면 됩니다.

seoleda의 이미지

ㄹㄹㄹ 님의 의견은 잘 들었습니다. 하지만, 두 수가 오차범위내에 있을 경우 같다고 판단할 경우, 과연 계산식에서 얼마나 오차가 누적될런지는 잘 모르겠습니다.
계산과정의 오차를 무시해 버리자는게 아니라, 단순히 < em>동등비교연산에 한해서 단순한 비트열을 비교하는 것이 아니라, 오차를 가만한 친절한 연산을 제공했으면 더 좋을것 같아서 얘기를 꺼내봤습니다. 잠깐 ANSI/ISO C standard 문서를 찾아 봤는데, 실수의 동등비교연산자를 어떻게 수행 하라는 얘기는 없는것 같습니다.

여러분은 이 두수는 비트열이 같으므로 같다. (실제로 내부에서 이런식으로 비교 하는지는 잘 모르겠습니다), 이 두수는 오차범위내에 있으므로 같다. 중 어떤것이 더 마음에 드시는지요? 저는 후자가 더 마음에 듭니다. 이유는
컴파일러에서 전자와 같은 행위는
1. floating point는 오차가 있다는 사실을 모르는 사람에게는 혼란을 일으킬 만한 행동이며,
2. 위 사실을 아는 사람에게는, 아 이 두 수는 오차범위내에서 같구나 라는 사실을 유추 할 수 있기 때문에 입니다.
뭐 엄연히 다른 수를 같다고 할 수 있느냐? 라는 의견에는 할말이 없습니다만, 여러분들의 고견을 듣고 싶습니다.^^

p.s. 그런데, 한계를 인정한 정직한 정의라는 표현은 참 마음에 듭니다.

chadr의 이미지

거기까지 컴파일러가 알아서 해줘버리면 실제로 발생하는 오차를 측정할 방법은 전혀 없습니다. 사실 컴파일러 차원에서도 얼마나 오차가 발생하여야지 같다고 정의 할것인가도 모호하구요..

실 예로 3차원공간에 물체가 있다고 합시다.. 여기에서 0.001, 0.003, 0.002 에 있는 점과 0.0011, 0.0031, 0.0021 에 있는 점은 엄연히 위치가 다른 곳입니다. 이런 오차 허용범위를 정의하고 조절해야 하는 자는 해당 코드를 구현하는 구현자이지 컴파일러가 임의적으로 하긴 어려운 범위입니다.
-------------------------------------------------------------------------------
It's better to appear stupid and ask question than to be silent and remain stupid.

-------------------------------------------------------------------------------
It's better to appear stupid and ask question than to be silent and remain stupid.

zeon의 이미지

다른 방법을 택했지 않았을련지요...

a가 0일때도 생각해 주세요....
몫은 cinsk님에게..

저는 졸려서...==333

God said it. I believe it. That settles it.

여친이 길르는 용..

unipro의 이미지

우리가 수학시간에서 배우던 수와 컴퓨터에서 수를 표현하는 자료형은 엄연히 다릅니다. 보통 특별한 언급이 없으면 수학에서는 무한한 집합을 대상으로 처리하지만, 컴퓨터의 자료형은 유한한 집합을 대상으로 합니다. 그래서 오버플로우니 언더플로우가 등장하는 것이겠죠.

다들 아시겠지만, 정수를 컴퓨터에서 표현한 것은 보통 integer라는 자료형이고, 실수는 float이라는 자료형이죠. 문제는 완벽하게 표현할 수 없다는 것이죠. integer나 float에서 최대값과 최소값이 존재하는 것은 모두들 알고 있습니다. 그런데 float에서 정밀도가 있다는 것은 가끔 잊어버리는 분들이 계시더군요. 수학에서 실수는 연속성을 가지지만, float 자료형은 이가 빠진 톱니처럼 아주(?) 띄엄띄엄 존재합니다. 따라서 최대값과 최소값 사이에도 표현할 수 없는 수가 무한히 많이 존재합니다. 이것들에 대해서 고려해야 하겠죠.

이것은 단순히 float 자료형을 처리하는 방법으로는 정확한 처리가 불가능합니다. 하드웨어적인 한계이기 때문입니다. 만약에 프로그램에서 사람이 분수나 제곱근을 처리하듯히 연산하고 그렇게 표현한다면 가능할 듯 싶습니다. 그러나 속도가 많이 느려지겠죠.(이렇게 속도를 희생하면서 정밀도가 필요한 분야가 얼마나 있을지 모르겠습니다.) 일반적으로는 위에서 cinsk님이 제시한 방법으로 하는 것이 제일 좋을 듯 싶습니다. 더 빠는 속도를 원한다면, float 대신에 int로 하고 출력할 때 적절하게 변환해도 되겠죠.

내 블로그: http://unipro.tistory.com

~~~의 이미지

그런 연산이 필요한 분야가 아주 아주 많이 있습니다. 그래서 maple, mathematica 같은 computer algebra system 에는 말씀하신 것처럼 최대한 symbolic computation 을 한 후 마지막에 numerical computation 을 하는 기능이 있습니다. 일종의 lazy evaluation 이지요. 그리고 하드웨어에서 지원하는 부동소수점형 이외에 무한 정밀도로 사용할 수 있는 수 타입을 제공하구요. 무한 정밀도 자료형은 꼭 computer algebra system 이 아니더라도 많은 언어에 기본 형 또는 기본 라이브러리로 포함되어 있습니다. 필요한 데가 많이 있기 때문이지요.

puaxx의 이미지

creazy -> crazy

=3=3=3

ssehoony의 이미지

프로그래밍 하시는 분이면 컴퓨터 아키텍쳐 중에서
정수 표현법인 2의 보수법과 float 이나 double 표현법인 IEEE754 정도는 숙지하고 계셔야 합니다.

2의 보수법을 숙지 하지 못하면, int i = -100 일때
"i * 2" 와 "i << 1" 이 동일할꺼라고 짐작 것과 seoleda님의 질문은 컴퓨터의 내부적으로 숫자를 어떻게 저장하고 핸들링을 하지는 모르기 때문에 생기는 문제이지요.

소수점부분의 오차 문제는

수학적으로 이야기를 하자면
모든 10진수 정수는 2진수로 표현이 가능하지만
10진수 소수는 간혹 2진수로 표현할때 10진수로는 유한소수인데도 불구하고
2진수에서는 무한소수가 되는 경우가 있습니다.
반대로 1/3 같은경우 10진수에서는 무한소수이지만 3진수에서는 유한소수가 되지요.

다시 컴퓨터로 넘어와서
위의 무한소수나 혹은 매우 많은 자릿수를 갖는 소수는 컴퓨터의 자료구조에 담을 수가 없을 것이라는 것은 쉽게 아실 듯 하구요.
그래서 자료를 담을수 있는 한계점에서 올림 혹은 내림, 반올림을 발생하게 됩니다. 그때 생기는 오차가 결과적으로 우리가 보는 오차 이지요.

체스맨의 이미지

왜 글을 입력하면 중간에 잘리죠... -_-;;;

Orion Project : http://orionids.org

체스맨의 이미지

위에서도 언급됐지만 cinsk 님께서 제시하신 식은 a 가 0 일 때 문제가 있습니다.

제가 보아온 수치해석 루틴들은 EPS 값을 인자로 받는 경우도 있고, 고정값으로 적용하는 경우도 있습니다만, 대개는 위의 식처럼 비교값에 따라 스케일하지는 않습니다.

저는 다음과 같은 함수를 정의해서 사용합니다. 즉 -eps ~ +eps 사이 값은 0으로 처리하는 것입니다. 두 값을 비교하려면 두 값의 차를 입력하면 되겠죠.

int
realCompareToZero( double val, double eps )
{
	return val>eps ? 1 : val

그 다음, EPS 및 INF 값은 다음과 같이 정의해서 사용합니다. 다음 값들은 경험적으로 그리고 상용 소프트웨어 등으로부터 얻은 값들입니다. NUMERIC EPS 값은 대개 고정밀도 수치연산에, GEOMETRIC EPS 는 3차원 모델의 위상 관계에, ALLOWABLE 및 ROUGH 는 저정밀도 수치 연산에 이용합니다.

#define REAL_EPS_NUMERIC    1e-15
#define REAL_EPS_GEOMETRIC  1e-10
#define REAL_EPS_ALLOWABLE  1e-8
#define REAL_EPS_ROUGH      1e-5
#define REAL_INF_NUMERIC    1e15
#define REAL_INF_GEOMETRIC  1e10

IMATH 개발 도구에 정의되어 있고,
IMATH

IMAML 같은 3차원 모델링 라이브러리에 적용된 바 있습니다.
IMAML

음... Filtered HTML 로 쓰니, 이유를 모르게 글 중간에서 잘리네요...

---------------

Coral Library Project : http://coral.kldp.net
Orion Project : http://home.megapass.net/~heesc22/

Orion Project : http://orionids.org

댓글 달기

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