ByteStream에서 EOF 표현

hyungjunn·2024년 6월 30일
0

Java에서 모든 Byte Stream 관련 클래스들은 InputStream, OutputStream에 기반을 두고 있다. 이 두 클래스는 abstract class이고 이에 따른 abstract method가 딱 하나있다. read메서드다. 그런데 의문점이 든다. 분명 byte 관련한거니까 return 값이 byte여야 하는거 아닌가? 왜 int일까? 링크에 첨부된 Javadoc에서는 다음과 같이 설명한다.

Reads the next byte of data from the input stream. The value byte is returned as an int in the range 0 to 255. If no byte is available because the end of the stream has been reached, the value -1 is returned.

byte는 0~255까지 값으로 나타낼 수 있다. (1byte는 8bit고 2진수로 00000000~11111111까지 나타낼 수 있기 때문이다. 그리고 여기에서 얘기하는 0~255는 Java에서의 byte가 아니라, 저수준의 데이터를 표현할 때 쓰는 unsigned byte를 의미한다.)

이 0~255까지를 데이터를 표현하면 되지만, 파일을 더 이상 읽어들이지 못하는 끝지점을 표현할 수 있는 수단인 EOF를 표현할 수 없었다. 그래서 이 byte에서 int로 변환시켜 표현하는 것을 택했다. 그리고 그 EOF의 값은 일반적으로 -1로 표현한다. 그렇다면 0~255의 값중에서 -1을 표현하고 싶으면 어떻게 해야할까? 이것에 대한 수많은 자료들 중 Ben Eater의 Twos complement: Negative numbers in binary만큼 잘 설명하는 자료를 찾아보진 못했다. 아래에서는 이 동영상을 참고하여 쓴 글이다.


Sign Bit

간단하게 여기서부터는 1~7까지만 생각해본다.(8은 2^3으로 다 표현하려면 4칸을 넘어버려 명확하게 설명하는데 조금 방해된다.) 0그리고 1~7까지의 숫자를 나타내보면 다음과 같다.

그리고 음수를 표현해주기 위해 아무런 역할을 안하고 있는 맨 앞자리를 Sign Bit로 둔다. 이 sign bit가 0이면 음수를 1이면 양수를 나타낼 수 있게 된다.

그러면 이제 검증을 해보자. 1 + (-1) 은 몇이 되나.

0001 + 1001 => 1010 => 1010에 해당하는 숫자는 -2다. 한가지 문제가 더 있는데, 0은 부호가 없어서 두 가지의 값이 나타나면 안된다. 하지만, 그림을 보면 0000, 1000 이렇게 두가지가 나타내질 수 있다는 문제점이 생긴다.


Ones Complement

Ones Complement는 Sign Bit때와 양수 그리고 0은 똑같이 나타낸다. 하지만, 음수를 나타낼 때는 숫자를 완전히 뒤집는다. 0은 1로 1은 0으로 뒤집어 음수를 정의한다.

마찬가지로 검증을 해보자. 1 + (-1) 은 1111 이 된다.(실제로 해보면 10000이나 네자리까지만 반영되기 때문에 마지막 1은 고려하지 않는다.) 하나만 더 해보자. 4 + (-4) 는? 1111이 된다. 즉, 부호가 반대인 것끼리 더하면 0이 된다. 하지만 여전히 0000이란 값의 0이 하나 더 있었다. 이 문제는 5 + (-3) 같은 곳에서 나온다.

0 1 0 1 :5
1 1 0 0 :-3

--
0 0 0 1 :1(위의 그림을 보면 대응되는 값이다.)
결국 0이 두가지가 있기 때문에 예상했던 값(2) 보다 한칸 밀리는 1이 나오게 된 것이다.


Two Complement

그렇다면 결국 Ones Complement 에서 0이 두 개인 문제만 해결하면 된다. 그리고 이것을 해결하기 위해 음수들과 0인 0~-7을 한칸씩 밀어 -1~-8로 나타내었다. 한칸씩 밀어냈다는 뜻은 1을 더해줬다는 말과 같다.

마지막으로 검산을 통해 증명해보자. 1 + (-1) 은 0(10000)이 된다. 7 + (-7) 은 0이 된다.


위의 과정을 쭉 따르면 결국 1을 -1로 만들 수 있다.
1. 1(0001)의 Ones Complement로 -1을 나타낸다. (0을 1로 1을 0으로) -1(1110)
2. Two Complement로 -1을 나타내주기 위해 1을 더해준다. -1(1111)

이렇게 OutputStream,InputStream 에서 EOF를 표현하기 위해, 1을 -1로 바꾸고, byte를 int로 변환한다.

0개의 댓글