C에서 수치 값들의 표현 범위

for1003의 이미지

limit.h를 열어보면...

SCHAR_MIN -127
INT_MIN -32767
...

로 되어 있네요..

정수 표현에 의하면... signed char는 -128 ~ 127
signed int는 -32768 ~ 32767의 범위를 가질텐데...

왜 이렇게 최소값이 1이 차이가 나는 걸까요?

errai의 이미지

제가 사용하는 리눅스 서버(레드햇 8)의 limits.h는 정확하게
적혀있습니다.

# define SCHAR_MIN (-128)
# define SCHAR_MAX 127

RPM 버전 : glibc-2.2.93-5

pynoos의 이미지

0 을 양수 범위에 넣고 생각하시면, +, - 갯수가 같죠..

winner의 이미지

CPU 가 수처리를 할 때 1의 보수를 사용하나요?

'C 언어 펀더멘탈' 을 보면 C 표준에 최소값을 최대값에 부호만 바꾼 값과 같거나 혹은 부호를 바꾼 값보다 1이 작아야 한다고 나옵니다.

사용 환경이 매우 궁금하네요.

for1003의 이미지

제가 정확하게 문제를 적어놓지 않았습니다..

지금 C99 draft 문서를 보구 있는데요..

SCHAR_MIN -127
INT_MIN -32767

로 되어 있네요..
그래서, 혹시나 확인차 K&R Appendix를 찾아보니.. 위와 같이 되어 있습니다.

gcc, vc++에 있는 limits.h에 열어보니..
SCHAR_MIN (-128)
로 되어 있습니다.

제가 궁금한 것은 왜 표준 문서에서는 저렇게 1이 차이가 나냐는 것이지요...
뭔가 이유가 있는 것 같은데.. 곰곰히 생각을 해봐두 잘 모르겠습니다.
^^;

lsj0713의 이미지

C언어 표준은 적어도 다음 3개 이상의 signed integer의 내부적인 표현법을 가정하고 있습니다. (C99 6.2.6.2 Integer types p2) 대부분의 C 컴파일러에선 보통 2의 보수 표기법을 많이 사용하지만, 다른 표기법을 사용하더라도 이상할 것이 없습니다.

2의 보수 (two’s complement)
1의 보수(one’s complement)
부호-크기 표기법(sign and magnitude)

이런 이유로 C 표준이 요구하는 signed integer형의 최소 범위는 -(2^n - 1) ~ 2^n - 1 (여기서 n은 value bit의 갯수) 이 되는 것입니다. (C99 5.2.4.2.1 Sizes of integer types <limits.h>) 만약 수의 범위가 이렇게 음수 양수의 범위가 같게 될 경우 수 하나(sign bit가 1이고 모든 value bit가 0 또는 1 일때)가 남게 되는데, 남는 하나의 수는 사용되지 않거나 negative zero라는 값이 됩니다. (C99 6.2.6.2 Integer types p2)

물론 대부분의 C 컴파일러들처럼 signed integer형의 범위를 -(2^n) ~ 2^n - 1로 해도 전혀 표준에 위배되는 것이 아닙니다. '최소 범위'라는 말에 주목하십시오.

winner의 이미지

FCD 를 보고 계시나요? 아니면 IS 를 보고 계신가요?

IS 는 제가 안봐서 모르겠군요.

제가 아는 바에 의하면 위에 적어놓은 것과 같습니다.
거기에 있는 수는 표준이 보장하는 최소범위입니다.

그런 것이 아니라면 문서에 Implementation defined 라고 적혀 있을 겁니다.

즉 표준이 보장하는 것이 아니라 하나의 예를 들어 놓은 것입니다.

위에도 적었듯이 1의 보수나 부호크기표현(sign and magnitude representation) 을 쓸 경우를 위해 표준은 그렇게 요구하는 것이죠.

사실 저는 FCD 도 제대로 안 봤는데 'C언어 펀더멘탈'에 의하면 유부호 정수의 최소값과 최대값을 더하면 0 이나 -1 이 나와야 한다고 합니다.

전웅의 이미지

lsj0713 wrote:
C언어 표준은 적어도 다음 3개 이상의 signed integer의 내부적인 표현법을 가정하고 있습니다. (C99 6.2.6.2 Integer types p2) 대부분의 C 컴파일러에선 보통 2의 보수 표기법을 많이 사용하지만, 다른 표기법을 사용하더라도 이상할 것이 없습니다.

2의 보수 (two’s complement)
1의 보수(one’s complement)
부호-크기 표기법(sign and magnitude)

OP 께서 물으신 주제는 다른 분들께서 이미 잘 설명해 주셔서... 딴지는
아니지만 지나가는 길에 사소한 이야기 하나를 적으려고 합니다 - 아마도
C99 에서 바로 copy & paste 하신 것 같아서...

제 책에서도 적은 내용으로 기억합니다만, "2의 보수" 와 "1의 보수" 의
올바른 영어 표현은

two's complement
ones' complement

입니다. C 표준 (C99) 에 나와 있는 표기는 잘못된 것이며 오래 전에
project editor 에게 지적해 다음 revision 에 수정하기로 약속이 되어
있습니다.

그럼...

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

lsj0713의 이미지

전웅 wrote:

제 책에서도 적은 내용으로 기억합니다만, "2의 보수" 와 "1의 보수" 의
올바른 영어 표현은

two's complement
ones' complement

입니다. C 표준 (C99) 에 나와 있는 표기는 잘못된 것이며 오래 전에
project editor 에게 지적해 다음 revision 에 수정하기로 약속이 되어
있습니다.

다소 C와는 관계 없는 질문이 될 것 같아서 다른분들에게 좀 죄송스럽습니다만...

one's complement와 ones' complement는 무슨 차이가 있습니까? 영어 밑천이 없는지라 왜 전자가 틀린 것인지 알수가 없습니다. 죄송하지만 설명을 부탁드리는 바입니다. ^^;

전웅의 이미지

lsj0713 wrote:
전웅 wrote:

제 책에서도 적은 내용으로 기억합니다만, "2의 보수" 와 "1의 보수" 의
올바른 영어 표현은

two's complement
ones' complement

입니다. C 표준 (C99) 에 나와 있는 표기는 잘못된 것이며 오래 전에
project editor 에게 지적해 다음 revision 에 수정하기로 약속이 되어
있습니다.

다소 C와는 관계 없는 질문이 될 것 같아서 다른분들에게 좀 죄송스럽습니다만...

one's complement와 ones' complement는 무슨 차이가 있습니까? 영어 밑천이 없는지라 왜 전자가 틀린 것인지 알수가 없습니다. 죄송하지만 설명을 부탁드리는 바입니다. ^^;

알고 계시겠지만, "one's" 는 단수의 소유격, "ones'" 는 복수의 소유격
입니다. 즉, 어색하게나마 우리말로 그 차이를 표현하자면, "ones'
complement" 는 "1들의 보수" 가 되는 것입니다.

1의 보수와 2의 보수의 이름의 차이는 각 보수를 만드는 방법에서 연유
합니다. 2의 보수 (two's complement) 는 *하나*의 2 를 여러번 제곱해
만든 수에서 보수를 구하지만,

100000000b - 10101010b = 01010110b

1의 보수 (ones' complement) 는 *여러개*의 1 로 이루어진 수에서 보수를
구하는 차이가 있습니다.

11111111b - 10101010b = 01010101b

사소하지만 Knuth 가 지적했듯이 많은 전공서와 심지어는 국제 표준에서도
잘못 쓰이고 있는 표기입니다.

그럼...

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

windy96의 이미지

lsj0713 wrote:
C언어 표준은 적어도 다음 3개 이상의 signed integer의 내부적인 표현법을 가정하고 있습니다. (C99 6.2.6.2 Integer types p2) 대부분의 C 컴파일러에선 보통 2의 보수 표기법을 많이 사용하지만, 다른 표기법을 사용하더라도 이상할 것이 없습니다.

2의 보수 (two’s complement)
1의 보수(one’s complement)
부호-크기 표기법(sign and magnitude)

이런 이유로 C 표준이 요구하는 signed integer형의 최소 범위는 -(2^n - 1) ~ 2^n - 1 (여기서 n은 value bit의 갯수) 이 되는 것입니다. (C99 5.2.4.2.1 Sizes of integer types <limits.h>) 만약 수의 범위가 이렇게 음수 양수의 범위가 같게 될 경우 수 하나(sign bit가 1이고 모든 value bit가 0 또는 1 일때)가 남게 되는데, 남는 하나의 수는 사용되지 않거나 negative zero라는 값이 됩니다. (C99 6.2.6.2 Integer types p2)

물론 대부분의 C 컴파일러들처럼 signed integer형의 범위를 -(2^n) ~ 2^n - 1로 해도 전혀 표준에 위배되는 것이 아닙니다. '최소 범위'라는 말에 주목하십시오.

C 언어 표준 자체가 2's complement 외의 표현을 용납하고 있는지에 대해서는 모르겠습니다만.. 실질적인 구현의 측면에서 2's complement를 하지 않으면 안 됩니다.

무슨 소린고 하니.. cpu에서는 모두 2's complement로 수를 표현하고 있다는 겁니다. c 언어의 특징 중의 하나가 machine과 1:1로 대응되게 알아먹을 수 있는 표현을 쓴다는 것인데 그게 1's complement라든지 sign and magnitude라든지 하면 곤란해지지요.

그래서...
practical answer는 c 에서는 2's complement를 가정한다가 되겠고...
general answer는 cpu의 표기법에 의존한다가 되겠습니다..

(1's complement를 사용하면서 cpu에서는 2's complement로 처리한다? 이런 어이없는 경우는 제외하겠습니다..)

vacancy의 이미지

전에 어떤 과목 교수님이셨더라 -_-a
( 아마;; Digital System Design이었던 것 같습니다. )
여튼 수업을 듣다가 들었었는데요.

one's complement와
ones' complement는 둘다 쓰이고 있다고 합니다.

예전에는 앞쪽의 것이 주로 쓰였었는데,
현재는 대체로 뒤쪽의 것을 쓴다고 들은 것 같네요. :roll:

전웅의 이미지

vacancy wrote:
전에 어떤 과목 교수님이셨더라 -_-a
( 아마;; Digital System Design이었던 것 같습니다. )
여튼 수업을 듣다가 들었었는데요.

one's complement와
ones' complement는 둘다 쓰이고 있다고 합니다.

예전에는 앞쪽의 것이 주로 쓰였었는데,
현재는 대체로 뒤쪽의 것을 쓴다고 들은 것 같네요. :roll:

특정 표기가 잘못된 것이니 절대 사용하지 말아야 한다는 강력한 주장은
아니었습니다만, "one's complement" 라는 표기 자체가 실제 쓰이고 있다
해도 엄밀한 의미에서 올바른 표기는 아님을 알리고자 한 것입니다 - 특히
lsj0713 님이 revision 이 약속된 C 표준의 부분을 copy & paste 하신 것
같기에... 전혀 다른 개념을 가리키는 "two's complement", "twos'
complement" 와는 달리 "one's complement" 와 "ones' complement" 는
오해의 여지가 없기에 섞어 쓰는 것이 의사소통에 문제를 일으키지는
않습니다.

그럼...

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

전웅의 이미지

windy96 wrote:
C 언어 표준 자체가 2's complement 외의 표현을 용납하고 있는지에 대해서는 모르겠습니다만.. 실질적인 구현의 측면에서 2's complement를 하지 않으면 안 됩니다.

더 정확히는 "two's complement 를 하지 않을 이유가 많지 않습니다" 정도
가 되어야 합니다. "하지 않으면 안 된다" 는 불가능의 늬앙스를 갖습니다.

windy96 wrote:
무슨 소린고 하니.. cpu에서는 모두 2's complement로 수를 표현하고 있다는 겁니다.

흠... "현대 CPU 에서는 거의 모두 2's complement로 수를..." 로 고쳐야
올바른 사실이 됩니다. 과거부터 지금까지 생산된 모든 종류의 CPU 가 음수
표현에 모두 two's complement 를 사용한 것은 아닙니다 - 제가 들은 일례
로 CDC 6600 은 ones' complement 를 사용했습니다.

또한, 눈을 DSP 쪽으로 돌리면 음수 표현에 two's complement 를 사용하지
않는 경우를 더 많이 찾아볼 수 있으며, 사소한 문제일 수 있지만 수치해석
분야에서는 negative zero 를 통해 얻을 수 있는 장점도 있습니다 - 동일한
이유로 IEEE 754 에는 negative zero 가 도입되어 있습니다. 또한, CPU 가
two's complement 를 사용한다고 해도 반드시 가장 작은 음의 정수의
절대값이 가장 큰 양의 정수보다 하나 크다는 보장도 없습니다. two's
complement 에서도 all-bits-one representation 은 trap representation
으로 예약해 다른 목적 (예를 들면, integer arithmetic 을 위한 NaN 혹은
negative zero) 을 위해 사용할 수 있습니다 - 이를 C 언어의 정의 (최소한
C99) 가 허락하고 있습니다.

더 현실적인 문제로 눈을 돌리면, 현대의 machine 과 그 machine 에서
생성된 data 가 1sC 와 SM 과 무관하다해도, 과거의 machine 에 의해 생성
된 data 를 지금도 다루어야 하는 경우라면 C 언어의 1sC 혹은 SM 지원이
중요합니다 - 프로그래머의 생각보다 프로그램은 수명이 길고, 프로그램의
수명보다 그 프로그램이 만든 자료의 수명은 더 깁니다 - (이미 겪은 the
year 2000 혹은 앞으로 닥칠 the year 2038 problem 이 그 예입니다).
더구나 앞으로 특수한 목적을 위해 제작될 CPU 나 DSP 가 1sC 나 SM 을
사용하는 경우라도 C 언어가 배제되지 않고 사용될 수 있다는 사실도 결코
무시할 수 없는 부분입니다.

windy96 wrote:
c 언어의 특징 중의 하나가 machine과 1:1로 대응되게 알아먹을 수 있는 표현을 쓴다는 것인데 그게 1's complement라든지 sign and magnitude라든지 하면 곤란해지지요.

오히려 그 반대입니다. C 언어의 특징 중 하나가 말씀하신대로 machine 과
1:1 대응을 이룰 수 있는 것이기에 1sC 와 SM 표현을 허락하는 것이 매우
중요한 것입니다. C 언어가 2sC 표현을 배제하는 것이 아니기에 언어의
정의가 다른 표현을 추가로 허락한다는 사실은 2sC 표현을 사용하는
machine 에서 프로그래밍 하는 것에 아무런 영향을 주지 않습니다 - 오직
매우 큰 이식성을 고려하는 사람들에게만 영향이, 그리고 1sC 와 SM 표현을
사용하는 machine 에서 프로그래밍 하는 사람들에게만 축복이 있을
뿐입니다.

windy96 wrote:
그래서...
practical answer는 c 에서는 2's complement를 가정한다가 되겠고...
general answer는 cpu의 표기법에 의존한다가 되겠습니다..

문제가 "C 언어라면" 모든 종류의 CPU 에 의존하는 것이 아닙니다. 예를
들어, BCD 나 grey code 등은 C 언어에 의해 받아들여지지 않은 표기입니다.

windy96 wrote:
(1's complement를 사용하면서 cpu에서는 2's complement로 처리한다? 이런 어이없는 경우는 제외하겠습니다..)

과거 생성된 자료를 convert 하기 위해 구식 CPU 를 emulate 하는 등의
경우는 결코 "어이없는" 경우가 아닙니다.

그럼...

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

익명 사용자의 이미지

기록으로 남김니다.

2의 보수 체계에서 -INT_MIN == INT_MIN 이기 때문에, abs() 류 함수는 양수를 보장하지 않습니다.
abs(INT_MIN) == INT_MIN 으로 여전히 음수입니다.

이걸 고려해서 프로그래밍하는 사례를 본 적이 없는데, 관련 정보가 있으면 코멘트 부탁드립니다.

익명 사용자의 이미지

n1256 wrote:
7.20.6 Integer arithmetic functions
7.20.6.1 The abs, labs and llabs functions
Synopsis
#innclude <stdlib.h>
int abs (int j);
long int labs (long int j);
long long int llabs (long long int j);

Description
The abs, labs, and llabs functions compute the absolute value of an integer j. If the result cannot be represented, the behavior is undefined.265)
Returns
The abs, labs, and llabs, functions return the absolute value.

265) The absolute value of the most negative number cannot be represented in two’s complement.

네 맞습니다. 2의 보수를 이용한 음수 표기에서 int형 최소값의 절대값은 int로 표현 가능하지 않습니다. 표준의 주석(265)에서도 언급하는 내용입니다.

문제는, 주어진 수의 절대값이 표현 가능하지 않을 때 abs 함수의 동작은 undefined behavior라는 겁니다. 컴파일러는 우리가 기대하지 않은 결과를 줄 수 있을 뿐만 아니라, 아예 일관성 없는 동작을 보일 수도 있습니다.

C언어를 어셈블리 언어 대신 쓰시면서, 내 코드는 x86에서만 동작할 예정이니 이식성이나 undefined behavior 같은 건 신경 쓸 필요가 없고, 당연히 x86 CPU의 방식대로 음수를 다뤄 줄 거라고 생각한다면, 아래와 같은 코드에서 빅엿을 먹을 겁니다.

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
 
void is_the_absolute_value_nonnegative(int x){
	int abs_x = abs(x);
	printf("abs(%d) = %d, %s\n", x, abs_x, abs_x>=0?"non-negative":"negative");
}
 
int main(void) {
	is_the_absolute_value_nonnegative(-10);
	is_the_absolute_value_nonnegative(0);
	is_the_absolute_value_nonnegative(10);
	is_the_absolute_value_nonnegative(INT_MAX);
	is_the_absolute_value_nonnegative(INT_MIN);
	return 0;
}

실행 결과 예시: https://ideone.com/txBUGR

ㅋㅋㅋ. 여러분들의 컴파일러에서도 테스트해 보세요. 물론 최적화 옵션이라던가 그런 것에 따라 달라질 수도 있습니다.

컴파일러는 abs(x)의 값이 undefined behavior를 유발하는 경우가 아니라면 항상 non-negative라는 걸 알고 있으므로, 그냥 항상 non-negative라고 못박은 채 최적화를 진행해 버릴 수 있는 겁니다. 그 결과 이런 이상한 출력이 나올 수 있는 것이죠.

그냥 C언어에서 부호 있는 정수를 다룰 땐 어떤 경우에도 표현 범위를 벗어나지 않도록 프로그래머 스스로 최대한 주의를 기울이는 편이 좋습니다. 그러지 못한 경우 사소한 버그부터 보안 취약점까지 참 다양한 일이 일어날 수 있습니다.

shint의 이미지

https://msdn.microsoft.com/ko-kr/library/s3f49ktz.aspx?f=255&MSPPError=-2147217396

signed char 의 범위는 -128 ~ 127
unsigned char 의 범위는 0 ~ 255

signed int –2,147,483,648 ~ 2,147,483,647
unsigned int 0 ~ 4,294,967,295

말씀하시는건. short int 인가 봅니다.
signed short int 2 –32,768 ~ 32,767
unsigned short int 2 0 ~ 65,535

short int 는 2바이트의 크기를 가집니다.
http://codepad.org/T1L26SDR

----------------------------------------------------------------------------
젊음'은 모든것을 가능하게 만든다.

매일 1억명이 사용하는 프로그램을 함께 만들어보고 싶습니다.
정규 근로 시간을 지키는. 야근 없는 회사와 거래합니다.

각 분야별. 좋은 책'이나 사이트' 블로그' 링크 소개 받습니다. shintx@naver.com

댓글 달기

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