부동소수점

파일:Z3 Deutsches Museum.JPG|섬네일|200px|초기의 전기기계식 프로그래밍 가능한 컴퓨터 Z3에는 부동소수점 산술 기능이 포함되었다. (뮌헨의 국립 독일 박물관)
'''부동소수점'''(浮動小數點, floating point) 또는 '''떠돌이 소수점''' 방식은 실수를 컴퓨터상에서 근사하여 표현할 때 소수점의 위치를 고정하지 않고 그 위치를 나타내는 수를 따로 적는 것으로, 유효숫자를 나타내는 가수(假數)와 소수점의 위치를 풀이하는 지수(指數)로 나누어 표현한다.
컴퓨터에서는 고정 소수점 방식보다 넓은 범위의 수를 나타낼 수 있어 과학기술 계산에 많이 이용되지만, 근삿값으로 표현되며 고정 소수점 방식보다 연산 속도가 느리기 때문에 별도의 전용 연산 장치를 두는 경우가 많다. 고정 소수점과 달리 정수 부분과 소수 부분의 자릿수가 일정하지 않으나, 유효 숫자의 자릿수는 정해져 있다.
β를 밑으로 하는 k-부동소수점수 x는 다음 형태를 가진다.
:
여기서 인 정수이고, bi는 인 정수이다. 를 '''가수부'''라 하며, e는 '''지수부'''라고 한다. 만약  혹은 이라면, 이 부동소수점수 x는 '''정규화되었다'''고 한다.
대부분의 컴퓨터에서 사용하는 이진법으로 정규화된 부동소수점수를 나타낸다면, 위 형태에서 β=2이고, 가수부는 0이나 1의 수로 채워진다. 이때 가수부 첫째 수는 1이다.
:
실제 컴퓨터에서는 보통 이진법을 사용하여 다음과 같이 세 부분의 값으로 실수를 나타낸다.
* 부호부 (1비트) : 양수일 때는 0, 음수일 때는 1
* 지수부 (부호가 없는 정수, 8비트) : 8비트로 표시
* 정규화된 가수부 (부호가 없는 정수, 23비트) : 제일 앞의 비트는 정규화되었으므로 1이다.
예를 들어, 십진수 21.8125를 정규화된 이진수로 나타낸다고 해보자. 소수점 위의 (21.)10=(10101)2이고, 소수점 아래 (0.8125)10=(0.1101)2이다. 즉 (21.8125)10=(10101.1101)2이며, 이를 정규화하면 0.101011101×25이다. 지수의 5를 이진법으로 바꾸면 101이다. 따라서, 32비트 정규화된 부동소수점수로 나타낸다면 맨 앞 비트의 부호는 0(양)이고, 지수부 부호는 0(양)이며, 지수부 나머지 7개 비트는 0000101, 가수부는 101011101000…이 된다. 이것을 결합하면 (00000010110101110100000000000000)2가
된다.
IEEE 754는 전기 전자 기술자 협회(IEEE)에서 개발한 컴퓨터에서 부동소수점을 표현하는 가장 널리 쓰이는 표준이다.
IEEE 754의 부동 소수점 표현은 크게 세 부분으로 구성되는데, 최상위 비트는 부호를 표시하는 데 사용되며, 지수 부분(exponent)과 가수 부분(fraction/mantissa)이 있다.
center
; 예시
−118.625 (십진법)을 IEEE 754 (32비트 단정밀도)로 표현해 보자.
*음수이므로, 부호부는 1이 된다.
*그 다음, 절댓값을 이진법으로 나타내면 1110110.101이 된다. (이진기수법을 참조)
*소수점을 왼쪽으로 이동시켜, 왼쪽에는 1만 남게 만든다. 예를 들면 1110110.101=1.110110101×2⁶ 과 같다. 이것을 정규화된 부동소수점 수라고 한다.
*가수부는 소수점의 오른쪽 부분으로, 부족한 비트 수 부분만큼 0으로 채워 23비트로 만든다. 결과는 11011010100000000000000이 된다.
*지수는 6이므로, Bias를 더해야 한다. 32비트 IEEE 754 형식에서는 Bias는 127이므로 6+127 = 133이 된다. 이진법으로 변환하면 10000101이 된다.
이 결과를 정리해서 표시하면 다음과 같다.
파일:Float point example frac.svg
부동 소수점 표현 방식은 수를 (가수)×(밑수)(지수)와 같이 유효숫자를 사용한 곱셈 형태로 표현한다. 예를 들어, -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'가 된다.
지수부에는 따로 부호 비트가 없기 때문에 음수 지수를 처리하기 위해 보통 바이어스 표현법을 사용한다. 즉, 할당된 자릿수로 표현 가능한 전체 영역을 반으로 나누어, 작은 영역에는 음수값 및 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.1과 0.01을 표현하지 못하므로 0.1의 제곱이 0.01이 되지도 않고 0.01과 가장 가까운 수가 되지도 않는다. 24비트 단정밀도 표현에서, 십진수 0.1은 지수 = -4; 가수 = 110011001100110011001101 이고 그 값은,
:정확히 0.1000000014901161193847656256이다.
이 수를 다시 제곱하면,
:정확히 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 또는 단정밀도에서 −0.8742가 된다.
부동소수점 덧셈과 곱셈은 모두 교환법칙 (''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'') × ''c'' 은 ''a'' × ''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비트를 사용한다. 16비트로 처리하는 반정밀도(half precsion)에서는 부호 1비트,지수부 5비트 가수부 10비트를 사용한다.
과거의 마이크로소프트 제품은 자체 규격인 MBF(Microsoft Binary Format)를 사용했다. 이 형식에서는 배정밀도에서 부호 1비트, 지수 8비트, 가수 55비트를 사용하여 상대적으로 표현 범위가 좁은 대신에 유효숫자가 많으므로 보다 정밀한 값을 표현할 수 있다. 다만 실제 연산 과정에서는 IEEE 754 규격은 80비트 연산을 수행하므로, 연산 자체는 IEEE 754가 정밀하다.
* IEEE 754
* 비정규 값(denormal number)
=== 내용주 ===
=== 참조주 ===
* 
 
분류:컴퓨터 산술