부동소수점과 엔디안 논하기 [CSAPP Chap 2]

다룬다고 생각은 해도 참 와닿지 않는 두 주제이다. 어쨌든 2장에서 다루는 것도 있지만 이후의 내용들에서도 나올 수 있는 만큼 책을 읽어 내려가는데 있어 나름의 배경지식이라고 여기는 것도 좋은 학습 자세라고 생각한다. 2장의 핵심 내용은 여기서 마무리 된다고..


부동소수점 수

  • 1,230,000은 1.23 * 10^6과 같다 그치? 이걸 그대로 컴퓨터에 적용하게 된다.

부동소수점이라 불리는 float는 32비트 = 4바이트로 구성되어있다 :

  • 1비트는 부호. 숫자의 음수 여부를 결정한다. boolean isMinus
  • 8비트는 지수. 소수점의 위치를 결정한다. 2^x에서 x를 맡는다
  • 23비트는 가수. 실제 숫자 부분을 나타낸다. 앞의 예제에서, 1.23을 말한다

부동소수점은 이 셋의 구성을 합쳐서 표현한다. 그리고 부동은 Not Moving 아님

 

지수를 소개합니다 (사람 지수 말고)

  • 지수는 8비트이니 255까지 저장 할 수 있다. 우리는 무척 작은 수도 표현해야되서 양수/음수 지수 모두 필요하다.
  • 2의 보수 같은걸 안쓰고 양수 지수를 표현하기 위해 바이어스 표현법을 사용했다.
    • 32비트에선 바이어스 값이 127로 정해져있는데, 실제 지수값에 이 값을 더해서 저장하는 방식이다.
    • 2^10을 저장하고자 한다면, 10 + 127 = 137을 저장한다.

와 그럼 255 - 127 의 결과보다 넘는 값은 못쓰겠네요.

네. 질문에 도움은 안되겠지만 지수 필드의 양쪽 끝은 에약되어있다.

  • 모두 11111111 이면, 숫자가 무한대이거나, 숫자가 아니다의 Not a Number(NaN) 부여
  • 모두 00000000 이면, 0이던가, 0에 아주 가까운 Denormalized Number이다.
  • 그래서 범위는 -126 부터 +127까지이다.

 

예제 : -0.75 표현하기

  • 우선 절댓값으로 바꾸고 이걸 2진수로 바꾼다. 정수는 2로 나누지만 여긴 2를 계속 곱하기로 하자.
  • 0.75 * 2 = 1.5
    • 1이 나오고 0.5가 남았다.
  • 0.5 * 2 = 1.0
    • 1이 나오고 끝!
  • 10진수 0.75는 2진수로 0.11이 되었다.

 

  • 0.11을 1.xxxx * 2^y 형태로 바꿀건데, 이걸 정규화라고 부른다.
  • 0.11의 소수점을 우측으로 한칸 옮기면 1.1이 될 것이다.
    • 원래 숫자에 2를 곱해서 만들어졌으니, 전체 값이 변하지 않도록 뒤에 2^-1를 다시 곱하기로 한다.
    • 이제, 0.11은 1.1 * 2^-1 이 되었다.

그래서..

  • 부호인 1비트는 isMinus이니 1이다.
  • 지수를 표현하는데 바이어스를 쓰니 -1 + 127 = 126해서, 01111110으로 저장한다.
  • 1.1 * 2^-1에서 소숫점 이후 부분인 .1를 가수로 표현해야한다.
    • 게다가 입력 형식도 다르단다. 보통 1이 맨 오른쪽에 오는데, 이건 맨 왼쪽이 1이다.
    • 그래서 23칸 중 22칸이 0이된다. 10000000000000000000000
  • 1 01111110 10000000000000000000000
  • 이걸 다 합치면 -0.75가 완성된다.

 

부호 없는 정수의 덧셈과 오버플로우

  • 컴퓨터의 계산 능력에는 한계가 있어 정해진 워드 크기를 넘으면 예상 못한일이 일어난다.
    • 부호없는 4비트 기준으로 10 + 8을 해보면 : 1010 + 1000 = 1 0010 = 2  18이 어떻게 2임?
  • 2의 보수에서도 해보자. 2의 보수에 4비트 컴퓨터는 -8부터 +7까지 가능하다.
  • 5 + 5는 = 0101 + 0101 = 1010이니 -6이 된다.
    • 이게 어떻게 -6인가 보니.. 맨 앞 1은 -8, 뒤의 010은 +2라고 한다.

 

2의 보수를 사용하는건 컴퓨터 단위로 봐야하는가 변수 단위로 봐야하는가 : 둘 다

  • 컴퓨터 단위 : CPU 내 산술연산장치는 2의 보수 덧셈을 하도록 설계되어있다.
  • 변수 단위 : 컴파일러가 변수의 타입을 보고 하드웨어가 계산한 결과의 오버플로우 발생 여부를 대응한다.

 

 

Endia nn e ss

  • 숫자 0x0123567을 저장한다고 해보자.
    • 16진수니까 한 자리는 4비트이니 두 자리는 1바이트, 즉 01 23 45 67 이렇게 저장한다.
      하지만 컴퓨터 아키텍처에 따라 저장하는 순서가 다르다.
  • 빅 엔디안 : 사람이 읽고 쓰는 방식을 따라간다. 01 저장, 다음에 23, 다음에 45, 다음 67
  • 리틀 엔디안 : 반대로, 덜 중요한 67부터 먼저 저장한다. 개인용 컴퓨터와 스마트폰이 해당한다.

서로 다른 엔디안 시스템끼리 네트워크로 데이터를 주고 받을 때 바이트 순서를 해석하지 못하면 완전히 다른 값으로 인식하기 때문이다.

리틀 엔디안이

  • 0x100 : 0x34
  • 0x101 : 0x12

를 저장했다고 하면, 실제 저장된 값은 0x1234인 것이다.