부동소수점

위키백과, 우리 모두의 백과사전.
Bliimoa (토론 | 기여)님의 2015년 5월 11일 (월) 18:21 판

부동소수점(부동소수점, 浮動小數點)[1] 방식은 실수를 표현할 때 소수점의 위치를 고정하지 않고 그 위치를 나타내는 수를 따로 적는 것으로, 유효숫자를 나타내는 가수(假數)와 소수점의 위치를 풀이하는 지수(指數)로 나누어 표현한다.

컴퓨터에서는 고정 소수점 방식보다 넓은 범위의 수를 나타낼 수 있어 과학기술 계산에 많이 이용되지만, 근삿값으로 표현되며[2] 고정 소수점 방식보다 연산 속도가 느리기 때문에 별도의 전용 연산 장치를 두는 경우가 많다. 고정 소수점과 달리 정수 부분과 소수 부분의 자릿수가 일정하지 않으나, 유효 숫자의 자릿수는 정해져 있다.

원리

부동 소수점 표현 방식은 수를 (가수)×(밑수)(지수)와 같이 유효숫자를 사용한 곱셈 형태로 표현한다. 예를 들어, -0.4를 밑수가 10인 부동 소수점으로 나타내면 -0.04×101이 되며 밑수가 2이면 -0.8×2-1가 되는데, 가수 부분을 한자리 자연수를 갖도록 바꾸면 -4×10-1과 같이 된다. 이처럼 가수의 첫째 자리가 밑수보다 작은 한자리 자연수가 되도록 바꾸는 것을 정규화라고 한다. 예를 들어, 앞의 값은 밑수가 2이면 -0.8×2-1이 되는데 이것을 정규화하면 -1.6×2-2이 된다. (여기서 볼 수 있듯이 밑수가 2일 때 정규화하면 가수부분의 첫째 숫자는 항상 1이 된다.)

컴퓨터 프로그래밍이나 전자계산기 등에서는 밑수가 10인 경우에 로마자 E 또는 e를 사용하여 함수 형태로 표시하기도 하는데, -0.4는 -0.04E+1 또는 -0.04e+1이 되며, 정규화하면 -4E-1 또는 -4e-1로 쓴다. 만약, 사용할 밑수를 미리 정해 놓는다면 가수와 지수만으로 실수를 표현할 수 있는데, 앞의 보기에서 밑수를 10으로 고정한다면 실수 -0.4는 가수 -4와 지수 -1의 조합으로 나타낼 수 있다. 보다 정형화된 형태로는 가수부와 지수부의 자릿수를 고정할 수 있는데, 만약 밑수는 10이고 부호는 따로 표시하며, 가수부 5자리, 지수부 3자리로 하는 형식이라면 앞의 값 -0.4는 '부호 -, 가수 40000, 지수 -005'로 나타낼 수 있다. 밑수가 2일 때에 정규화 결과 가수의 첫째 자리는 항상 1이 되므로 표시를 생략할 수 있다. 따라서, 고정된 형식에서 가수부에 1자리를 더 표시할 수 있게 되므로, 처리할 수 있는 유효숫자가 1자리만큼 늘어 난다. 앞의 예 1.6×2-2를 이 방식으로 표현하면 '부호 +, 가수 60000, 지수 -002'가 된다. (가수 1.6에서 1이 생략되고, 유효숫자는 6자리까지 가능하게 된다.)

실제 컴퓨터에서는 보통 이진법을 사용하여 밑수를 2로 하고, 다음과 같이 세 부분의 값으로 실수를 나타낸다.

  • 부호부 (1비트)
  • 지수부 (부호가 있는 정수)
  • 가수부 (부호가 없는 정수)

이때, 값을 먼저 이진수로 변환한 후에 정규화하고, 그것을 다시 정형화된 형식으로 표현한다. 먼저 부호는 1비트로 실수가 양수일 때는 0, 음수일 때는 1로 표현한다. 지수부에는 따로 부호 비트가 없기 때문에 음수 지수를 처리하기 위해 보통 바이어스 표현법을 사용한다. 즉, 할당된 자릿수로 표현 가능한 전체 영역을 반으로 나누어, 작은 영역에는 음수값 및 0, 큰 영역에는 양수값이 차례대로 1:1 대응되도록 한다. 예를 들어, 지수부를 8비트로 표현한다면 모두 256가지 수를 나타낼 수 있는데 이것을 반으로 나누어 음수 127개와 0, 양수 128개를 차례대로 대응시킨다. 따라서, 비트열 00000000은 지수 -127을 나타내고, 01111111은 지수 0, 11111111은 지수 128을 나타낸다. 일반적으로는 지수부가 n비트일 때 (2n / 2 - 1 = 2n-1 - 1)을 지수 값에 더하며 이것을 바이어스 상수라고 한다. (다만, 지수부의 모든 자리가 모두 0 또는 1인 경우는 각각 0 또는 무한대를 나타내는 등 종종 특수한 목적으로 예약되어 있다.) 가수부에서는 정규화 결과 유효숫자의 첫째 자리는 언제나 1이므로 표시하지 않고, 소수 부분만 표현한다.

예를 들어, 앞의 보기와 같이 실수값 -0.4을 16비트 부동소수점으로 처리하되, 가수부는 10비트, 지수부는 5비트라면, 먼저 값을 이진수로 변환하면 0.0110011001100110(2)이고, 정규화 결과는1.10011001100110(2)×2-2이므로, 가수는1.10011001100110(2), 지수는 -10(2)이 된다. 음수값이므로 부호부는 '1'이 되고, 지수는 5비트이므로 바이어스 상수는 25-1 - 1 = 15이다. 따라서, 지수부는 '01101'이 된다. 가수부는 소수 부분만 10비트로 나열하여 '1001100110'이 된다. 부호-지수-가수의 순서로 조합하여 16비트 1011011001100110를 얻는다.

정확도 문제

부동 소수점으로 표현한 수가 실수를 정확히 표현하지 못하고 부동 소수점 연산 역시 실제 수학적 연산을 정확히 표현하지 못하는 것은 여러가지 문제를 낳는다.

예를 들어, 0.1과 0.01을 표현하지 못하므로 0.1의 제곱이 0.01이 되지도 않고 0.01과 가장 가까운 수가 되지도 않는다. 24비트 단정밀도 표현에서, 십진수 0.1은 지수 = -4; 가수 = 110011001100110011001101 이고 그 값은,

정확히 0.100000001490116119384765625 이다.

이 수를 다시 제곱하면,

정확히 0.010000000298023226097399174250313080847263336181640625 이다.

단정밀도 부동 소수점 (반올림 있는) 하드웨어에서 제곱을 한다면,

정확히 0.010000000707805156707763671875 이다.

하지만 0.01과 가장 가까운 표현 가능한 수는

정확히 0.009999999776482582092285156250 이다.

또한, π (및 π/2)를 표현하지 못하므로 tan(π/2)가 무한대의 값이 나오지 않으며 오버플로(overflow)가 생기지도 않는다. 따라서 π/2를 정확히 표현하지 못하기 때문에 일반적인 부동소수점 하드웨어에서는 tan(π/2)를 계산하는 일이 불가능하다. C 언어에서 아래의 계산 결과는 16331239353195370.0 가 된다.

  double pi = 3.1415926535897932384626433832795;
  double z = tan(pi/2.0);

단정밀도에서는 (tanf 함수를 이용하여), −22877332.0 라는 결과를 얻는다.

같은 이유로 sin(π)는 0이 되지 않고 배정밀도에서 약 0.1225×10^-15 또는 단정밀도에서 −0.8742×10^-7가 된다. [3]

부동소수점 덧셈과 곱셈은 모두 교환법칙 (a + b = b + a 이고 a × b = b × a)이 성립하지만, 꼭 결합법칙이 성립하지는 않는다. 즉, (a + b) + c 이 항상 a + (b + c) 과 같지는 않게 된다. 예를 들면 7자리 부동소수점(Float 7) 10진수 계산을 할 때:

 1234.567 + 45.67846 = 1280.245
                       1280.245 + 0.0004 = 1280.245
 그러나 
 45.67846 + 0.0004 = 45.67886
                     45.67886 + 1234.567 = 1280.246

또한 항상 분배법칙이 성립하지도 않는다. 즉, (a + b) × ca × c + b × c과 다를 수 있다:

 1234.567 × 3.333333 = 4115.223
 1.234567 × 3.333333 = 4.115223
                       4115.223 + 4.115223 = 4119.338
 그러나 
 1234.567 + 1.234567 = 1235.802
                       1235.802 × 3.333333 = 4119.340

유효 숫자를 잃어버리는 문제 뿐만 아니라, π와 0.1를 정확하게 표현하지 못하는 문제와 다른 약간의 부정확성이 다음과 같은 현상을 일으킨다:

  • 소거: 거의 같은 두 값을 빼는 것은 정확성을 매우 많이 잃게 된다. 이 문제가 아마도 가장 일반적이고 심각한 정확도 문제이다.
  • 정수로의 변환 문제: (63.0/9.0)을 정수로 변환하면 7이 되지만 (0.63/0.09)는 6이 된다. 이는 일반적으로 반올림 대신 버림을 하기 때문이다.
  • 제한된 지수부: 결과값이 오버플로되어 무한대값이 되거나 언더플로되어 비정상 값 또는 0이 될 수 있다. 만약 비정상 값이 되면 유효숫자를 완전히 잃어버린다.
  • 나눗셈이 안전한지 검사하는데 문제가 생김: 제수(나눗수)가 0이 아님을 검사하는 것이 나눗셈이 오버플로되고 무한대값이 되지 않는 걸 보장하지 않는다.
  • 같음을 검사하는데 문제가 생김: 수학적으로 같은 계산결과가 나오는 두 계산 순서가 다른 부동소수점 값을 만들어낼 수 있다. 프로그래머는 어느정도의 허용 오차를 가지고 비교를 수행하지만, 그렇다고 해서 문제가 완전히 없어지지 않는다.

규격

실제 사용되고 있는 부동 소수점 방식은 대부분 IEEE 754 표준을 따른다. 이 규격에서는 실수를 32비트로 처리하는 단정밀도(single precision)에서는 부호 1비트, 지수부 8비트, 가수부 23비트를 사용하며, 64비트로 처리하는 배정밀도(double precision)에서는 부호 1비트, 지수부 11비트, 가수부 52비트를 사용한다. 4배정도(quadruple precision)에서는 128비트로 부호 1비트, 지수부 15비트, 가수부 112비트를 사용한다.[4]

과거의 마이크로소프트 제품은 자체 규격인 MBF(Microsoft Binary Format)를 사용했다. 이 형식에서는 배정밀도에서 부호 1비트, 지수 8비트, 가수 55비트를 사용하여 상대적으로 표현 범위가 좁은 대신에 유효숫자가 많으므로 보다 정밀한 값을 표현할 수 있다. 다만 실제 연산 과정에서는 IEEE 754 규격은 80비트 연산을 수행하므로, 연산 자체는 IEEE 754가 정밀하다.

각주

  1. 정보통신표준용어에 따른 표기. 순화용어는 "떠돌이 소수점"이다.
  2. 본래 이진법에서는 십진수 소수가 정확히 표현되지 않는다.
  3. 하지만 cos(π)는 정확히 −1이 된다. 도함수가 π 근처에서 0에 가까우므로, 인자의 부정확함이 −1 근처의 부동소수점 수들의 간격보다 훨씬 작아지고 따라서 반올림한 결과는 정확하게 나온다.
  4. 이 16바이트 규격은 IEEE 754 규격서에 직접 명시되어 있지는 않다.

참고자료

같이 보기