2.2-Integer_Representations

bit로 Integer 를 표현하는 2가지 방법을 알아본다.
양의 정수를 표현하는 방법음의 정수를 포함한 모든 정수를 표현하는 2가지 방법이다.
사실 이 2가지 방법은 수학적 특성이나 machine-level 구현에서 연관성이 있다.
또한, 기존의 표현에서 다른 길이의 표현으로 옮기는 방법에 대해 살펴본다.

2.2.1 Integeral Data types

C언어는 다양한 정수형 데이터 타입이 존재한다.
이들은 32bit, 64bit 에 따라 "전형적인" 정해진 Byte 를 점유한다.
기본적으로 음수 표현을 지원하며, unsigned 키워드를 통해 양수만 표현함으로서 범위를 늘릴 수 있다.

한 가지 중요한 점은 음수가 가능한 절댓값이 정수보다 1 크다는 점이다.
ex) short : ~

machine 에 따라 다르기 때문에,
C언어 표준에서 보장하는 범위가 존재한다.
더 작은 범위이며, 양수와 음수의 절댓값 크기가 같다.

2.2.2 Unsigned Encodings

bit의 정수 표현을 이야기하면서, bit vector를 로 표현하거나,
각각의 bit를 표현하기 위해 라고 표현한다.
각각의 또는 의 값을 갖는다.

우리는 해당 bit vector를 양의 정수를 표현하는 함수로
를 정의한다. 해당 함수는 길이의 bit vector 를 양의 정수로 바꿔준다.
(Binary 2 Unsigned)
해당 함수는 다음과 같이 정의될 수 있다.

ex)

bit에 대해 해당 함수의 최댓값, 즉 bit 로 표현 가능한 최대 정수는
이다.
따라서, bit에 대한 표현 가능 범위는 이다.
이 함수의 중요한 특징은 특정 정수값 는 그에 해당하는 bit 표현법이 하나로 유일하다는 것이다.
즉, 일대일 맵핑이 가능하다.

is .(= + )
: (일대일 함수)
: for , is the (공역과 치역이 같다)

일대응 대응이기 때문에, 특정 정수는 bit vector 로 변환 가능하며, 반대로 bit vector 를 특정 정수로 표현 가능하다.
이를 역함수 라고 표현한다.

2.2.3 Two's - Complement Encodings

음수 표현은 보통 2의 보수 방식으로 표현된다.
우리는 이 방식을 라고 칭할 것이다. (Binary 2 Two's complement, length )

여기서 MSB(Most Significant Bit) 는 라고도 불린다. (부호를 결정하기 때문이다.)
양수 표현에 비해 이 마지막 bit, 번째 bit는 의 가중치를 가진다.

이로 인해, 이라면, 양수, 이라면 음수이다.

해당 가중치로 인해, 최솟값은 이며, 그 값은 이다.
반대로 최댓값은 이며, 그 값은 이다.

해당 함수 또한, bit vector 와 일대일 대응이 되는 이다.

is .(= + )

역시 역함수를 라고 표현한다.

2의 보수 즉, 정수 표현에서는 최솟값이 최댓값보다 절댓값이 크다.
구체적으로, 이다.

이 점은 간혹 문제를 일으키는데, 비트패턴의 절반은 음수가, 절반은 비음수가 차지한다.
근데, 이 포함되기 때문에, 양수 측이 표현할 수 있는 방법이 하나 적다.

Unsigned value 와 Signed Value 간에 다음과 같은 관계가 성립한다.

특이한 점으로 의 비트패턴은 Unsigned Value 에서는 최댓값, 즉 UMax 이다.
은 Signed, Unsigned 양쪽다 동일한 비트패턴을 가진다.

부호 비트를 사용하는 방법, 1의 보수 방법 등이 있으나,
2의 보수가 편리하기 때문에 2의 보수를 주로 사용한다.

N's Complements

- 길이의 숫자 에 대해, 의 보수는 이다.

여담으로... 수학적 구조 중에 군의 구조를 이룬다고 볼 수 있다.
특히, 에서의 modulo inverse 랑 비슷하게 더하기에 대한 역원으로 볼 수 있다.

2.2.4 Conversion between Signed and Unsigned

C언어에서는 같은 사이즈의 데이터 간의 casting 은 비트 표현을 바꾸지 않는다.
단, 해석이 바뀌기 때문에 그 값은 다르게 출력된다.
ex) short v = -12345, (unsigned) v 의 값은 53191 이다. (둘의 비트패턴은 동일하다.)

비트표현이 바뀌지 않지만, 값은 바뀐다는 점을 이용해,
라는 함수를 정의한다.(unsigned value 를 signed value 로 해석하기)

라고 정의할 수 있다. (정의그대로, 2의 보수로 표현된 값을 비트패턴으로, 그것을 다시 Unsigned value 로 해석한다) 단, 범위에 주의해야한다.

바로 계산할 수 있는 형태로는

성립하는 이유는 MSB 가 로 해석되는 것을 로 바꾸는 것이므로 를 더하면 된다.

또는, 비트표현에서 자리의 값으로 부호 판별이 되므로,

라고 할 수 있다.

도 비슷한 논의로 비슷하게 정의가능하다.

2.2.5 Signed versus Unsigned in C

C언어 표준은 부호 있는 정수 표현에 대해 규정하지 않지만, 대부분의 machine 은 2의 보수법을 사용한다.
보통 정수는 부호 있는 정수 표현으로 저장된다.

C언어는 부호 있는 표현, 없는 표현간의 casting 이 가능하다.
표준은 역시 그 방법에 대해서는 규정하지 않는다.
하지만, 대부분의 machine 은 비트패턴을 변하지 않는 상태로의 변환을 지원한다.

앞에서 계속 C언어의 표준과 그 구현을 같이 보고 있다.
표준은 보통 기능 자체를 제시하며, 그 구현은 구현체에 맡기는 경향이 있다.

이에 대한 GPT의 답변은
표준은 기능 제시 위주이며, 구현은 구현체, 컴파일러에게 맡기는 편이라고 한다.
이를 라고 한다고 한다.
그 이유로는 시스템 프로그래밍에 사용되는 만큼, 각 machine 에 맞게 최적화된 구현을 맡기려는 의도가 있다.

각 타입으로의 변환은 문법에 의해 몀명시적(explicit) 일수도, 암시적(implicit) 일 수 있다.

이 암시적 변환은 종종 이해할 수 없는 결과를 내거나, 버그를 일으키는 원인이 되기도 한다.
C언어는 음수가 아니라고 가정하고, 부호 있는 정수를 부호 없는 정수로 암시적으로 형변환한다.
이 때,

의 결과는 False 가 된다.
그 이유는 뒤의 는 부호없는 정수이다. 이에 따라 을 부호없는 정수로 암시적 형변환이 된다.
따라서,

이므로 False 이다.

2.2.6 Expanding the Bit Representation of a Number

큰 범위의 데이터를 작은 범위의 데이터 축소는 불가능할 수 있지만,
작은 범위의 데이터를 큰 범위의 데이터로 확장하는 것은 가능하다.

각 자료형의 한계값은 limits.h 에 저장되어 있다.
그 안에는
#define INT_MAX 2147483647
#define INT_MIN = (-INT_MAX - 1)
로 표현되어 있다.
이런 표기에는 2의 보수의 비대칭성, 즉 양수 음수의 표현범위가 다르다는 점이 포함되어있다.

Unsigned Number 에 대한 확장은 을 추가해주면 된다.
이 방법을 이라고 한다. 구체적으로,
,
의 길이, 의 길이라고 할 때,

이다.

Signed Number 에 대한 확장은 MSB의 값으로 채워주면 된다.
이를 이라고 한다.
,
의 길이, 의 길이라고 할 때,

이다.

조금 더 살펴보면, 양수일때는 MSB 가 0이기 때문에 과 동일하다.
반대로 음수일 때는 MSB 가 1이기 떄문에 1을 나열하는 것과 같다.
이 때, 1을 나열하는 것이 정말 같은 값을 표현하는지 생각해보면,
위의 표기를 이용하면,

이다. MSB 가 1임을 가정했다.
이때, 가 동일해지는 조건을 찾는다. (비트패턴과 그 값은 일대일 대응이다.)

이므로, 는 자명하게 이다.


, we will prove

변환에도 상대적인 순서가 존재한다.
먼저 size 에 대한 변환 후, 부호에 대한 변환을 거친다.
ex) short -> unsigned int
음수인 short 를 변환하면, 먼저 size 를 맞추기 위해 로 채워진다. 그 후, 부호변환이 일어나서
상대적으로 큰 수로 변한다.

2.2.7 Truncating Numbers

intshort 로, 다시 int 로 형변환을 하면, 저장하는 bit가 한번 줄어들었기 때문에
같은 int 지만 값이 달라진다.

더 작은 bit의 데이터로 줄어들 때, 그 차이만큼의 bit가 잘린다(truncate).
그 점 때문에 부호없는 정수에 대해,(Unsigned)
에 대해 bit가 잘려서 길이가 가 된 은 다음의 관계가 성립한다.

이유는 이하의 bit가 동일하고, 초과의 bit는 가중치가 를 인수로 가지기 때문에,
값이 0이다.

부호 있는 정수와 부호 없는 정수간 변환에 비트의 패턴이 바뀌지 않기 때문에,
부호 있는 정수에서도 비슷한 관계가 성립한다.
단, 부호 있는 정수에서는 이다.
부호 없는 정수로 값을 계산하고, 비트패턴이 안 변한다는 사실을 이용한 것이다.

2.2.8 Advice on Signed versus Unsigned

암시적 형변환은 티가 잘 나지 않기 때문에 여러 버그의 원인이 되곤한다.

	float sum_elements(float a[], unsigned length) {
		int i;
		float result = 0;
		for(i = 0; i <= length - 1; i++)
			result += a[i];
		return result;
	}

이 코드는 length = 0 일 때, 에러가 발생한다.

그 이유는, unsignedlength0 이 저장되어 있는데, lenth - 1-1 이 아닌, int_max 가 되기 때문에 의도하지 않은 메모리 접근이 발생한다.
따라서, i <= length - 1i < length 로 바꾸면 해결 가능하다.

	// library function
	size_t strlen(const char *s);

	int strlonger(char *s, char *t) {
		return strlen(s) - strlen(t) > 0;
	}

32bit 에서 size_tunsigned 로 정의되어 있다.

이 코드는 t 가 더 긴 문자열일 때, 즉, strlen(s) - strlen(t) < 0 일 때 문제가 생긴다.
이 때 해당 식의 값은 음수이나, unsigned 로 계산되기 때문에, True 라고 뜬다.
return strlen(s) > strlen(t) 로 해결 가능하다.

이러한 미묘한 버그로 인해, 최근 언어에서는 지원 자체를 안하는 경우가 많다.
java 는 모두 부호 있는 정수이며, >>>>> 로 분리하기도 한다.

부호 없는 정수는 우리가 수적 해석 없이 비트패턴으로서 해석할 때 도움이 된다.
이것은 우리가 로 해석하는 예시가 있다. 주소 또한 기본적으로 부호가 없다.
또한, 수학 관련 패키지, modulo, 다중정밀도 산술(큰 수에 대한 연산) 같이 숫자가 words 배열로 이루어진 곳에서 도움이 된다.