3.6. 실수 자료형의 이해

4 minute read

1. 실수 연산의 어려움

function countObvious(n) {
  let same = 0;
  for (let x = 1; x <= n; ++x) {
    let y = 1.0 / x;
    if (y * x == 1.0) {
      ++same;
    }
  }

  return same;
}
  1. \(\frac {1} {x} \times{x}\)인 x의 개수를 세는 함수
  2. countObvious(50)? 49
    • 버그인가?
    • CPU의 문제인가?
    • 실수 표현 방식의 문제 O

2. 실술와 근사값

2.1. 정수형

컴퓨터가 모두 정확하게 표현 가능

2.2. 실수형

컴퓨터가 모두 정확하게 표현 불가능

자료형 부호비트 지수비트 가수비트 지수범위 유효자릿수(십진수)
32비트 실수형 1 8 23자리 \(-2^7+2 \sim 2^7 -1(=-126 \sim 127)\) 6(float)
64비트 실수형 1 11 52자리 \(-2^10+2 \sim 2^10 -1(=-1022 \sim 1023)\) 15(double)
80비트 실수형 1 15 64자리 \(-2^14+2 \sim 2^14 -1(=-16382 \sim 16383)\) 18
  • 32비트의 경우: (부동 소수점 상수에 대한 제한
    • 지수 비트
      • 8비트로 총 256가지 표현 가능하지만, 0 표현 위해 0이 예약되어 있고, 255는 무한대 표현 위해 예약되어 있다
      • 실제로 사용할 수 있는 범위는 1부터 254까지이며,
        • 양수 127
        • 음수 -126
    • 지수범위: \(-2^{지수비트-1}+2 \sim 2^{지수비트-1}-1\)
    • 유효자릿수(Significant Digit): 표현할 수 있는 정밀도(Precision) 1. 최대: 3.402823466e+38F - 지수부(8): 1111 1110 - 가수부(23): 111 1111 1111 1111 1111 1111 2. 최소: 1.175494351e-38F - 지수부(8): 0000 0001 - 가수부(23): 000 0000 0000 0000 0000 0000

2.2.1 문제점

소수점 이하 자릿수 정확도의 문제

  1. 순환/비순환 무한소수의 경우 소수점 이하 자릿수가 무한함
  2. 모든 자릿수를 정확하게 표현할 수 없으므로 적절히 비슷한 근사값을 사용

2.2.2. 영향 요소

  1. 어떤 순서로 계산하는지
  2. 컴파일러 최적화를 켰는지

    x86 아키텍처에서 C++ 컴파일러 최적화 설정에 따라 64비트 실수형 변수를 내부적으로 80비트 실수 레지스터에 담은 채 그대로 사용할 수 있다

  3. 중간에 로그 메시지 출력하는지

    로깅 함수 호출 시 80비트 레지스터에 담긴 값을 스택에 잠시 저장하면서 이 값들이 64비트로 변경되고, 이때 잘려나간 부분에 있던 값들이 답에 영향

3. IEEE 754 표준

가장 많은 컴퓨터/컴파일러들에서 사용하는 실수 표기 방식

3.1. 내용

  1. 매우 방대한 규모의 표준
  2. 무한대, 비정규 수(subnormal number), NaN(Not a Number) 등의 특수한 ㄱ밧 존재
  3. 오버플로와 언더플로 처리
  4. 반올림에 관한 규정

3.2. 특징

3.2.1. 이진수로 실수 표기

  1. \(\frac {1} {2^i}\): 소수점 밑 i번째 자리의 크기
  2. 1011.101
    • 1011: \(2^3 + 2^1 + 2^0 = 8 + 2 + 1 = 11\)
    • .101: \(\frac{1}{2} + \frac{1}{2^1} = \frac{1}{2} + \frac{1}{8} = 0.625\)

3.2.2. 부동 소수점(floating-point) 표기법

3.2.2.1. 문제점

정수부/소수부에 사용 가능한 비트들을 어떻게 배분할 것인지의 문제

  1. 정수부에 많은 비트 사용 \(\rightarrow\) 소수부 정확도 떨어짐
  2. 소수부에 많은 비트 사용 \(\rightarrow\) 큰 수 표현 불가
3.2.2.2. 해결

위 문제 해결 위해 소수점을 옮길 수 있도록 함

3.2.2.2.1. 방식
  1. 소수점을 적절히 옮겨서 소수점 위에 한 자리만 남도록 한다
  2. 최상위 비트에서부터 표현할 수 있는 만큼 표시한다
  3. 나머지는 반올림한다
  4. 이진법으로 표현되므로, 소수점 앞의 숫자는 1만 가능하므로, IEEE 754에서는 소수점 앞의 1을 제외
3.2.2.2.2. 예제
  1. \[11.625 \rightarrow 2진법 \rightarrow 1001.101 \rightarrow 1.011101\]
  2. 1.011101 맨 앞에서부터 표현할 수 있는 만큼 표시
3.2.2.3. 실수 변수 구조
3.2.2.3.1. 저장 정보
  1. 실수는 \(263.3 = 2.633\times{10^2}\)처럼 정수부와 실수부로 구성
  2. 부호 비트: 양수/음수 여부
  3. 지수(exponent): \(10^2\)
  4. 가수(mantissa, 유효숫자): \(2.633 \times 10^2\)에서 2633이 유효 숫자
3.2.2.3.2. 예제
  1. 263.3
    • 263:
      • 정수부
      • 1 0000 0111
    • 0.3:
      • 소수부
      • 0.0100 1100 1100 1100
  2. 1 0000 0111 . 01001100110011…
    1. 1 . 0000 0111 0100 1100 1100 11…: 소수점을 앞을 8회 이동(\(2^8\))
    2. 부호비트: 0(양수)
    3. 지수 비트:
      • bias(32비트의 경우 127 = 0111 1111) + 지수(소수점 이동 횟수) = 127 + 8 = 135 = 1000 0111
      • bias를 더하는 이유는?
        • 지수는 부호 있는 값이며, 큰 값과 작은 값 모두 표현 가능
        • 하지만 부호 있는 값에서 2의 보수는 비교를 어렵게 함 \(\Rightarrow\) 지수를 부호 없는 수로 저장하여 비교하기 쉽게 만든다
        • 즉, 음의 지수 값을 양수로 표현하기 위해 bias를 더한다
    4. 가수 비트: 0000 0111 01001100110011…
  3. 최종적으로 비트는 다음과 같다
부호(1)   지수(8)        가수 비트(23)
0        1000 0111      0000 0111 0100 1100 1100 110

실수 비교하기

countObvious 함수

  1. \(\frac{1}{10}\times{3}\)과 \(\frac{3}{10}\)을 비교할 떄 둘 모두 신수 변수에 정확하게 담을 수 없으며, 표현할 수 있는 가장 가까운 실수로 근사해 표현
    1. \(\frac{1}{10}\times{3}\) 참 값보다 약간 큰 값
      1. \[\frac{1}{10}\]
      $$ 0.1\times{2} $$ = 0.2, Integral part: 0
      $$ 0.2\times{2} $$ = 0.4, Integral part: 0
      $$ 0.4\times{2} $$ = 0.8, Integral part: 0
      $$ 0.8\times{2} $$ = 1.6, Integral part: 1
      $$ 0.6\times{2} $$ = 1.2, Integral part: 1
      $$ 0.2\times{2} $$ = 0.4, Integral part: 0
      $$ 0.000110...\times{3} $$
      
      1. 3 = 0011
      2. \[0.000110\dots\times{0011}\]
    2. \(\frac{3}{10}\) 참 값보다 작은 값
      1. \[\frac{3}{10}\]
      $$ \frac{3}{10} $$
      $$ 0.3\times{2} $$ = 0.6, Integral part: 0
      $$ 0.6\times{2} $$ = 1.2, Integral part: 1
      $$ 0.2\times{2} $$ = 0.4, Integral part: 0
      $$ 0.4\times{2} $$ = 0.8, Integral part: 0
      $$ 0.8\times{2} $$ = 1.6, Integral part: 1
      $$ 0.6\times{2} $$ = 1.2, Integral part: 1
      0.10011
      

기타 링크

  1. 부동 소수점, 부동점 수, 부동소수점 표현
  2. IEEE 부동소수점, 컴퓨터 2진 부동소수점 표현
  3. 부동소수점
  4. 부동 소수점 계산의 정밀도 및 정확도
  5. float의 한계…
  6. [IEEE 754] floating point의 이해 (1))
  7. double vs float 정수형의 표현 범위.

Updated: