음수 0이 C언어에서 존재하는 값입니까?

나빌레라의 이미지

아래 제가 올린 파이썬 관련해서 한번 C로 작성해 봤습니다.

#include <stdio.h>
 
int main(int argc, int **argv)
{
	float p = 1.0;
	float n = 0.05;
 
	while (1){
		p -= n;
		printf("%f\n", p);
 
		if (p == 0.0){
			printf("break by equal 0\n");
			break;
		}
		if (p < 0.0){
			printf("break by lt 0\n");
			break;
		}
	}
}

결과는...

0.950000
0.900000
0.850000
0.800000
0.750000
0.700000
0.650000
0.600000
0.550000
0.500000
0.450000
0.400000
0.350000
0.300000
0.250000
0.200000
0.150000
0.100000
0.050000
-0.000000
break by lt 0

왠 음수 0????

제일 아래 메시지에서 보듯 == 0 에 걸려서 루프가 끝난 것이 아니라
< 0 에 걸려서 루프가 끝났습니다.

값이 0인데 0보다 작은 조건에 걸리다니...

뭔가 제가 컴퓨터의 float 표현에 대해 이해가 심하게 부족한것 같습니다.

ymir의 이미지

실수형은 쓸 일이 없다보니 그동안 모르고 있었는데..;; 재미있네요.

http://en.wikipedia.org/wiki/Signed_zero
http://en.wikipedia.org/wiki/IEEE_754-2008

되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』

익명 사용자의 이미지

int main(int argc, int **argv)
{
    float p = 1.0;
    float n = 0.05;
 
    while (1){
        p -= n;
        printf("%g\n", p);
 
        if (p == 0.0){
            printf("break by equal 0\n");
            break;
        }
        if (p < 0.0){
            printf("break by lt 0\n");
            break;
        }
    }
}
 
0.95
0.9
0.85
0.8
0.75
0.7
0.65
0.6
0.55
0.5
0.45
0.4
0.35
0.3
0.25
0.2
0.15
0.0999998
0.0499998
-1.56462e-07
break by lt 0
익명 사용자의 이미지

어떤 타입으로 선언하느냐에 따라서 다르지만 signed double, signed gloat, signed int, signed short, signed char형이면 음의 0을 가질 수 있습니다. 수를 메모리상에다 표현하면서 나온 문제(?)입니다. 나머진 위의 wikipedia의 IEEE관련 링크에 들어가보시면 아실겁니다.

planetarium의 이미지

아랫분 말씀대로 정수 타입엔 없고 실수 타입에만 있죠.
익명 사용자들간에 구분이 안되서 아쉽네요. 틀린 얘기 한번이라도 하면 크게 혼나야할 익명 사용자가 요새 한분 계신데...

익명 사용자의 이미지

정수형에 대해서도
2의 보수에서만 negative zero가 없습니다.
1의 보수나 부호-크기 표기법에서는 negative zero가 있을 수 있습니다.

그러나 이 문제는 negative zero에 관한 것이라기보다는
컴퓨터의 부동 소수점 표기상의 특성에 대한 것 같군요.
(혹은 10진-2진 간의 변환에 대한 문제점)

C99의 16진 상수를 도입하는 것도 생각해 볼 수 있겠으나,
부동 소수점 형식이라면 단순 크기 비교보다는 아주 작은 크기의 어떤 숫자값 eps를 상수로 정의해서

p == 0.0
p < 0.0

보다는
p > 0.0 - eps && p < 0.0 + eps
p < 0.0 + eps

식으로 비교를 함이 유리합니다.

planetarium의 이미지

찾아보니 ISO/IEC 9899:1999 에서는 정수형 타입을 위해 sign and magnitude, two's complement, one's complement 중의 한가지를 사용할수 있다고 하는군요 (6.2.6.2 항).
C언어의 느슨한 정의가 참 여러번 놀라움을 안겨주네요. 잘못된 발언 죄송합니다.

익명 사용자의 이미지

집에 가서 다시 생각해보니 위에 제가 쓴글은 잘못된게 맞습니다. 제 글은 무시를 ㅜㅜ
혼돈을 드려 죄송합니다 ㅜㅜ

planetarium의 이미지

???
signed short, signed char가 음의 0을 가질 수 있다고 쓴 분이고, 그게 실수였다고 말씀하시는건가요?
전 C언어 표준 문서까지 찾아가며 그 말씀이 맞다는걸 확인했는데... -_-;

익명 사용자의 이미지

가능하다는 것에 대해서 찾아주셔서 감사합니다만, 우리가 보아야 하는 경우는 특수한 경우(보수표현은 특수하다고 생각합니다.)를 제외한 일반적인 상황에서 생각해야 할 듯 합니다.
(일반적인 상황이란 연산체계가 잘 동작할때...)

위의 float형에서의 '-0'은 아마 machine epsilon과 printf문의 출력시 자릿수 문제가 겹쳐서 발생된 것일 겁니다.
(printf가 보통 자리수 표시하는게 소수점 이하 5자리인가 그런데 machine epsilon은 10^-??이니까 -(machine epsilon)이란 값을 printf에게 표시하게 하면, printf의 표시 자릿수 때문에 -0.00000으로 나올겁니다.
예전에 마니 봐왔던 것입니다.)
즉, 부동소수점에서 '일반적으로'는 -0은 없다는 것이 제 생각입니다.(특수한 경우를 제외하고 일반적인 사용에서요...)

두번째로 '일반적인 수 표시 체계'의 경우 signed int(32bit일경우)는

sign bit : 1bit
value bit : 31bit

입니다.

0은 0x00000000이고, -1은 0xffffffff가 됩니다. 그리고 -2^31은 0x70000000로 표현됩니다.
우리가 사용하는 값들도 옆의 값들처럼 사용한다고 알고 있습니다...
제 기억이 맞다면 산술연산 역시 이러한 표현식에 맞추어서 '일반적으로' 표현될 것 입니다.
이러한 수 표현(즉, 2진수와의 matching table)에 따르면 일반적으로 정수에서는 (보수를 생각안하면) -0은 없다고 생각됩니다.

보수의 표현식에 따르면 있지만, 일반적으로 코딩시에는 위의 표현식을 따른다고 가정을 하고 코딩을 하기 때문에 정수에서 -0은 없다고 볼 수 있고, 이런 의미에서 제가 잘못말씀드렸다고 한 것 입니다.^^;;

위의 두가지 근거(라거 쓰고 생각이라고 적습니다 ㅠㅠ)에 따라서 틀린 말씀을 드렸다고 생각해서입니다. ㅠㅠ

익명 사용자의 이미지

참고로... 사칙연산의 계산에서 쓰이긴 하지만... 일부러 보수 계산을 코딩상에서 하는 경우는 Simulation코드에서는 보기 힘들거든요^^;;
그래서 보수연산은 일반적이 아니라 특수한 경우라고 말씀드린 것입니다.

gilgil의 이미지

signed int signed short, signed char 타입에서 +0과 -0의 구분이 있나요?
2의 보수 체계에서 정수 타입이라면 +0과 -0이 존재하지 않을 것으로 보이는데...

snowall의 이미지

http://www.swarthmore.edu/NatSci/echeeve1/Ref/BinaryMath/NumSys.html

위의 글에 설명이 되어 있는 것 같은데요

결론적으로 signed int같은 형식에서는 -0은 없습니다.
signed int를 1바이트라 치고, 8비트 부호를 보면, 가령 00000000이 0이면 10000000은 -128이 되죠. 그리고 01111111은 127이고, 11111111은 -1이 됩니다.

그나저나 -0을 검색해보니 유사한 질문이 올라와 있군요...
http://www.velocityreviews.com/forums/t267991-signed-int-0-a.html

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

snowall의 이미지

http://en.wikipedia.org/wiki/Signed_number_representations

-0에 대해서는 위의 위키백과 페이지에 여러가지 사례가 있네요.

2보수 체계에서는 -0=+0이고, 1보수 체계에서는 -0!=+0입니다.

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

planetarium의 이미지

정확한 근거는 찾지 못했습니다만 영문 위키백과
http://en.wikipedia.org/wiki/Signed_zero
http://en.wikipedia.org/wiki/IEEE_754-1985
등에 따르면,
-0을 표시할수 있는 체계더라도
-0 != 0 은 false인듯 합니다.

snowall의 이미지

제가 위에 언급한 위키백과 페이지를 따른다면,

2보수 체계에서는 +0 = -0 = 0000 이고
1보수 체계에서는 +0 = 0000, -0 = 1111이 됩니다.

2보수 체계에서 0 = +0 = -0 = 0000 이라는 것은 아무도 이의가 없을 것이고,
1보수 체계에서 0 = +0 = 0000 이라는 것 또한 아무도 이의가 없을 것이라고 생각합니다.

1보수 체계에서, 2진수로만 따졌을 때, 0000 = 1111이라면 +0 = -0도 맞겠죠.

http://ko.wikipedia.org/wiki/1%EC%9D%98_%EB%B3%B4%EC%88%98

1보수 체계를 보면, 0000의 1의 보수는 1111에서 0000을 뺀거니까 1111이 맞습니다.
또한, 설명대로 본다면 부호만 바꾼 것이므로 +0의 1보수는 -0이 맞죠.

그래서, 제가 생각하기에는 1의 보수 체계를 쓴다면 +0!=-0이 맞다고 생각합니다.

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

planetarium의 이미지

!= 의 정의가 다른것 같습니다.
물론 0000과 1111이 다르지만, http://en.wikipedia.org/wiki/%E2%88%920_(number) 에 이런 구절이 있더라구요.
According to the IEEE 754 standard, negative zero and positive zero should compare as equal with the usual (numerical) comparison operators, like the == operators of C and Java.

bushi의 이미지

+0 에 대한 1의 보수가 0000 이라 하셨는데,
원래의 +0 을 2진수로 어떻게 표현하실 건지 여쭤봐도 될까요 ?

snowall의 이미지

"원래"를 어떤 의미로 사용하셨는지를 알려주신다면 좋겠습니다.

"+0에 대한 1의 보수가 0000"이라고 하신걸로 봐서, 혹시 오해하셨을지도 몰라서 명확히 설명하자면, 그 의미는 "정수의 2진수 표현을 1의 보수 체계를 사용하여 나타낼 때, +0은 0000이다"라는 뜻으로 사용한 것입니다. 오해 없으셨겠지만 사족을 달아둡니다.

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

bushi의 이미지

제가 헷갈린 것 같습니다.

쓰신 글의 말미에,
"또한, 설명대로 본다면 부호만 바꾼 것이므로 +0의 1보수는 -0이 맞죠."
에서 헷갈리기 시작했고,
부호-크기 표현법을 따른 음수의 표현과 1의 보수 체계를 사용한 음수의 표현을 섞인 상태서
(1-1) != (-1+1) 에서부터 거꾸로 올라가며 생각하다 뒤집어졌네요.

neogeo의 이미지

float 형은 그래서 항상 0 과 비교할때 직접 안하고 epsilon 이라는 오차한계도를 넣어서 비교합니다.

if ( abs(float_value) < EPSILON ) /* if ( float_value == 0 ) */

식으로 저는 항상 사용하고 있습니다. ( abs 는 상황에 따라 안쓰기도 하지만요 )

Neogeo - Future is Now.

neogeo의 이미지

0 하고 비교 뿐만 아니라 두 float 숫자가 같은가 비교할때도

#define EPSILON 1e-6f

이런걸 정의 해두고 항상

if ( abs ( float_a - float_b ) < EPSILON ) ) /* float_a == float b */

의 식으로 비교합니다.

Neogeo - Future is Now.

태훈의 이미지

덕분에 쓸 일이 거의 없어서 잊고 지냈던 부동 소수점에 대해 복습했습니다. :-)

Just do it!

klutzy의 이미지

부동 소수점에 대해서는 다른 분들이 충분히 답변해 주셨으니 정수에서의 -0을 정리해 보도록 하겠습니다. C99의 6.2.6.2를 참고로 했습니다.

위에서도 이야기가 나왔지만 C99에서는 signed integer에 대해서 세 가지 방법으로 표현할 수 있다고 합니다(6.2.6.2/2).

  • sign and magnitude: sign 비트로 양수/음수를 표현하고 나머지 비트로 값의 크기를 표현합니다.
  • 2의 보수
  • 1의 보수

그리고 시스템이 앞의 두 개(sign/magnitude, 2의 보수) 표현을 사용하는 경우 sign 비트가 1이고 나머지가 0인 값, 나머지 하나(1의 보수 표현)를 사용하는 경우 모든 비트가 1인 값이 "trap representation"이 될 수 있습니다. (이 경우 행동은 정의되지 않습니다.) 시스템 구현에서 이런 경우를 trap representation이 아닌 정상적인 값으로 처리할 수도 있으며, sign and magnitude와 1의 보수에서 이 값은 '-0'이 됩니다.

즉 -0은 C에서 존재할 수 있으며, 이것은 해당 시스템이 어떤 정수 표현법을 사용하는가와 -0에 해당하는 표현을 정상적인 값으로 지원하는가에 따라 결정됩니다.

시스템에서 -0을 지원하는 경우, 이 값은 비트 연산이나 사칙 연산, 대입문을 통해서만 생성할 수 있습니다. 또한, 그 경우에 정말 -0이 나오는 게 아니라 0이 나올 수도 있는데, 연산 결과가 -0이 아니라 0이 나오거나, 아니면 -0을 변수에 대입했더니 0이 될 수도 있습니다(6.2.6.2/3).

ymir의 이미지

부동 소수점 연산 많이 사용하신다면 gcc 의 -Wfloat-equal 옵션이 필요할 수도 있겠군요.

       -Wfloat-equal
           Warn if floating point values are used in equality comparisons.
 
           The idea behind this is that sometimes it is convenient (for the programmer) to consider floating-point values as approximations to infinitely precise real numbers.
           If you are doing this, then you need to compute (by analyzing the code, or in some other way) the maximum or likely maximum error that the computation introduces,
           and allow for it when performing comparisons (and when producing output, but that's a different problem).  In particular, instead of testing for equality, you would
           check to see whether the two values have ranges that overlap; and this is done with the relational operators, so equality comparisons are probably mistaken.

되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』

IsExist의 이미지

내용과는 상관없는 딴지지만

main(int argc, int **argv) 라고 사용하셨네요. ^^;

---------
간디가 말한 우리를 파괴시키는 7가지 요소

첫째, 노동 없는 부(富)/둘째, 양심 없는 쾌락
셋째, 인격 없는 지! 식/넷째, 윤리 없는 비지니스

이익추구를 위해서라면..

다섯째, 인성(人性)없는 과학
여섯째, 희생 없는 종교/일곱째, 신념 없는 정치

gilgil의 이미지

2's complement 를 사용하는 CPU가 대부분이라서 이런 것까지는 미처 생각을 하지 못하였군요.
아무튼 좋은 정보 얻고 갑니다. ^^

댓글 달기

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