jun-wiki

View My GitHub Profile

Posts (Latest 10 updated) :
Read all
Contents:
  1. 2.4 부동소수점
  2. 2.4.1 비율이진수
  3. 2.4.2 IEEE 부동소수점 1. 이건 두번째 레슨 1. 이제 세번째 레슨
  4. 2.4.3 숫자 예제
    1. 예시: e = 4비트, f = 3비트
      1. 부동소수점 표현 방식 요약
      2. 정수 → 부동소수점 변환 예시
  5. 2.4.4 근사법
  6. 2.4.5 부동소수점 연산
  7. 2.4.6 c에서의 부동소수점
  8. 2.5 요약



csapp 2.4다

여긴 real jot이니

집중하자

정수도 jot인데

소수는 big jot인건 상식

2.4 부동소수점

부동산…

움직이지 않는 자산이란 뜻이다

그리고 부동소수점은

움직이는 소수점이란 뜻이다…

$농담아니다$ (궁서체)

아닐 부(不) 가 아닌

뜰 부(浮) 다 ㅅㅂ

움직이지 않는게 아닌 “떠서” 움직여서
부동소수(float)이다

부동소수점은 수를 각각 $V=xw^y$ 의 형태로 표시한다

당연하다면 당연하게도 모든 수를 다 표시하진 못한다

애시당초 정밀도 보단 속도와 편의성에 투자헀으니 오차값 찐빠가 난다

그리고…

지금까지 사용하는 표준 부동소수점은

IEEE 표준 754 방식이다

I *triple
표준 754라고 말하며 멋들어지게 꺼드럭대보자

2.4.1 비율이진수

수를 $2^i$의 합으로 표현한다는 뜻2다

2진수의 소수는 2로 표현한다
그게 뭔소리냐…

예시) $[10.111] = 2^2 + 2^{-1} + 2^{-2} + 2^{-3}$

이렇게 쓴다는 말(horse라는 mean아님)이다

2.4.2 IEEE 부동소수점

IEEE 표준은 수를 $V = (-1)^s * M * 2^E$ 의 형태로 나타낸다

ㅅㅂ 또 jot같은 공식이네하고 넘기지 말아라

설명해주겠다

s는 음양을 표현한다

0이면 양수 1이면 음수…
그게 끝이다

존나 간단하니 더 설명 안하겠다

그럼 +0, -0 생기는 거 아니냐?

할 수 있는데 이건 뒤에서 설명하겠다

__

E는 예시부터 보자

예시)

0.0001100110011001 (2진법) = 1.100110011001 * $2^{-4}$

쉬프팅 덕에 이리 연산 가능하다는 건 알거다

소숫점을 옮긴만큼이 E다. 예시에선 -4가 E이다

M은 1.xxx에서 xxx를 담당한다

__


IEEE 표준 754에선
맨앞 부호 담당 비트를 s,
M의 담당 비트를 n,
E의 담당 비트를 e라고 정했다

크기도 정했는데

float (32bit) 에선 s = 1bit, e = 8bit, n =23bit

double (64bit) 에선 s = 1bit, e = 11bit, n =52bit

로 정했다

그리고 IEEE표준에선 3가지 케이스로 비트를 해석한다

기준은…

지수필드다

지수필드는 e나 E를 의미한다

아무튼 지수필드가 전부 0일때, 1일때, 그 외로 나뉜다
에지간해선 그 외일 거다

이를 정규화(Normalized)라 한다

이름보명 알 수 있듯이 normal(평범이라는 뜻)한 상황이다

지수필드의 경우 비부호로 표기한다

크기 비교 등 비부호가 더 간단하고 유용하니 말이다

전부 0일 떄와 전부 1일때인 255를 제외하면
1~254가 E가 있을 수 있는 범위다

원래라면 -128 ~ 127을 값을 가질 수 있는 E에
127을 더해 1 ~ 254로 바꿔준거다

여기선 127이 bias(보정값이라는 뜻)가 된다

아무튼 E를 어따가 쓰냐면

$0.0001100110011001$ (2) => $1.100110011001 * 2^{-4}$

-4가 E

e= E+127 = 123 이고 [01111011]로 표현가능하다

___

이번엔 M에 대해 알아보다

얜 가수(singer아님) 필드라고 부른다



1.xx...라고 표현할때 .xx...부분이다

1.xx...을 M, xx...부분을 보통 f라고 부른다

여기서 고대 프로그래머들의 티끌 모으기를 볼 수 있다

1.xx...가 되게 쉬프팅을 했기에

0.xx...일 때는 고려를 안해 1을 표현하는 비트를 안 써
무려 비트 하나를 아낄 수 있다

비트 하나하나 알차게 써먹된 고대 프로그래머들의 절약 정신을 느낄 수 있다…

여기까지 짠내가 나는 기분이고 말이다

__

그렇게 소수를 비트 배열로 인코딩 시 결과는

s(1)eeeeeeee(8)fffffffffffffffffffffff(23)이렇게 된다

위에 있는 수로 또 예시를 들자면
0/01111011/10011001100100000000000 = 0x3DCCC800
라는 거다

__


이건 두번째 레슨

e가 전부 0일때 이를 비정규화(denormalized)라고 한다

이때에는 $1.xx * 2{^-127}$ 이 아니라 $0.xx * 2{^-126}$라고 한다

왜 ㅅㅂ 라고 묻는다면

이렇게 하는게 더 범위를 넓게 쓸 수 있으니 말이다

전자를 쓰게 되면 최솟값이 $2^{-127}+2^{-150}$

후자를 선택하면 최솟값이 $2^{-149}$가 되어 더 작은 수 까지 표현 가능하다

(개구리가 따봉하는 그림)

이제 여기서 왜 +0, -0이 용인되는지 알려주겠다

정수 타입에선 0 2개를 막기 위해 염병을 하던 것과 달리

용인되는 이유는…

그야 의도되었으니까

$lim→0$ 같은 느낌이다

+0으로 수렴할떄랑 -0으로 수렴할때를 나누기 위해서 말이다

___

이제 세번째 레슨

e가 모두 1일때, 이를 특수 값이라고 표현

ㄹㅇ 말그대로 특수 값이라는 뜻으로

f가 전부 0이면 infinity취급하고

f가 0이 아니면 Nan(Not a Number)을 나타낸다

숫자로 취급하지는 않고 에러 출저나 다른 데이터 담을 때 사용한다

루트 -1이라 무한대 - 무한대 등 계산하면 리턴된다


2.4.3 숫자 예제

여기선 우리가 다룰 수 있을만큼 숫자를 낮추어 예제를 다뤄보겠다

예시: e = 4비트, f = 3비트

구분 비트 배열 지수 필드 (e, E, 2^E) 가수 필드 (f, M) 값 (2^E × M), V 10진수 값
0 (제로) 0 0000 000 0, -6, 1/64 0/8, 0/8 0/512, 0 0.0
비정규화 최소값 0 0000 001 0, -6, 1/64 1/8, 1/8 1/512 0.001953
비정규화 최대값 0 0000 111 0, -6, 1/64 7/8, 7/8 7/512 0.013672
정규화 최소값 0 0001 000 1, -6, 1/64 0, 8/8 (M=1) 8/512, 1/64 0.015625
정규화 값(1) 0 0111 000 7, 0, 1 0/8, 8/8 (M=1) 1 1.0
정규화 최대값 0 1110 111 14, 7, 128 7/8, 15/8 240 240.0
무한대 0 1111 000 - - -

부동소수점 표현 방식 요약

  • 비정규화 값
    • e 부분이 모두 0
    • 가수(M) = f/8
    • 값: 2^(-6) × (f/8) (여기서 -6은 bias 적용된 최소 지수)
  • 정규화 값
    • e 부분이 1도 아니고 0도 아님
    • 가수(M) = 1 + f/8
    • 값: 2^(E) × (1 + f/8)
  • 무한대
    • e 부분이 전부 1, f는 0
    • 값은 무한대(∞)

참고: 정규화 값에서 e의 bias를 적용해 실제 지수(E)를 계산
예시에서 bias는 2⁽ᵉ⁻¹⁾-1 = 7.


정수 → 부동소수점 변환 예시

예를 들어, 정수

00000000000000000011000000111001

을 부동소수점으로 변환하면,

  1. 1.xx… 형태로 정규화
    • 왼쪽으로 13칸 이동 (즉, E=13)
  2. 지수 필드 e 계산
    • bias=127 (float 기준) → e = E + bias = 13 + 127 = 140
    • e = 10001100
  3. 가수 필드 f 계산
    • 맨 왼쪽 1을 제외한 나머지 비트가 f
    • f = 100000011100100000000000000
  4. 부호 비트 s = 0 (양수)

최종 부동소수점 비트 배열:

0 / 10001100 / 100000011100100000000000000

Note: f 부분이 정수와 겹치는 구조임을 알 수 있다


2.4.4 근사법

당연하게도 모든 소수를 다루는 건 존나 무리다

그렇기에 우린 근사를 때린다

근사법은 네가지 방법이 있는데 한가지만 기억하면 된다

물론, 그 한가지가 좀 까다롭다

짝수근사법, 0방향근사법, 상향근사법, 하향근사법 4가지가 있다

하향근사법은 무조건 버림이다

ex) 1.6->1 / -1.5->-1

상향근사법은 무조건 올림이다

ex) 1.3->2 / -1.5->-1

0방향 근사법은 걍 소숫점 때면 된다

ex) 1.6->1 / -1.5->-1


마지막으로 짝수 근사법이다
부호 상관없이 중간 값이 짝수가 되도록 근사하는 방법인데…

말로하기 어려우니 예제와 함께 설명하겠다

01010001100100같이 비트가 주어지고
01010001100/100/로 나눈 떄까지만 보려 할때
/ 아래 값이 100이면 중간값이라 한다

100앞에 수가 1이면 +1, 아니면 버리면 된다

지금은 0100이니 걍 버려버리면 된다

2.4.5 부동소수점 연산

부동소수점의 덧셈과 곱셈의 방법은 나오지 않는다

대신 교환법칙등 특성만 서술한다

일단, 교환법칙이 성립한다
ex) x+y = y+x

하지만, 결합법칙은 성립하지 않는다

이유는 근사 때문이다

$3.14+1e10-1e10$ 이라고 할때 ($1e10$은 $10^{10}$)

$(3.14+1e10)-1e10 = 1e10-1e10$ = 0이 나온다.

그치만…

$3.14+(1e10-1e10)=3.14$

가 쳐 나와버린다

그러니 결합법칙은 주의하자


반면에 단조 특성이란 건 갖고 있다

$a >= b$이면
$a + c >= b + c$라는거다

웃긴건 정수는 오버플로우 때문에 단조성이 없다


부동소숫점의 곱셈
곱셈이 닫혀있다고 표현하는데

적절한 소수, 무한대, NaN중 하나로 값이 결정된다는 소리다

덧셈이랑 똑같이 교환법칙 성립하고 결합법칙 성립안하고 단조성 존재한다

똑같이 정수는 단조성 없다


2.4.6 c에서의 부동소수점

c에선 float과 double을 지원한다

그리고… 근사 할때 짝수 근사모드! 를 사용한다

그리고 타입 변환시 변경점이 적혀 있다

int -> float : 숫자가 근사된다

int, float -> double : 정확하게 보존된다

double -> float : 오버플로우 되서 무한되거나 근사된다
수가 너무 크거나 정수 표현 힘들면 에러라는 뜻으로 Tmin을 반환하기도 한다


2.5 요약

  • 컴퓨터는 정보를 비트로 인코딩하고 이를 연속된 바이트로 구성한다.

  • 정수를 표현하기 위해 2의 보수라는 방법을 사용했고 부동소수를 표현하기 위해 IEEE 표준 754를 사용했다.
  • 동일한 크기를 갖는 부호형, 비부호형 정수를 캐스팅할때 내부 비트는 변하지 않는다.
  • C에서 부호형과 비부호형을 연산하면 비부호형으로 묵시적 타입변환이되어서 종종 버그를 발생하기도 한다.
  • 정수의 덧셈과 곱셈은 수를 표현하는 범위가 한정적이어서 오버플로우를 발생할 수 있다.
  • 부동소수점도 마찬가지로 표현할 수 있는 범위가 한정적이므로 수를 표현 할 수 없을때 NaN 혹은 무한대로 표시하기도 한다.
  • 부동소수점 산술연산은 매우 조심스럽게 사용해야하는데 그 이유는 제한된 범위와 정밀도를 갖기 때문이며, (근사와 오버플로우(무한대))
  • 결합법칙이 성립하지 않아 일반적인 수학 법칙을 따르지 않는다.



___