[IEEE754] float, double 부동 소수점에 대해서

Posted by 앱해피
2015. 11. 28. 00:35 운영체제(OS)

컴퓨터에서 실수(real number)를 표현하기 위해 사용하는 방법은 여러가지가 있지만
그 중 가장 널리 사용되는 것은 IEEE 754 표준이다.

IEEE 754는 2진 표기법과 10진 표기법을 모두 정의하고 있지만
대부분의 아키텍처에서 2진 표기법을 사용하고 있는 것으로 알고 있으므로
여기서는 2진 표기법에 대해서만 다룰 것이다.

IEEE 754는 부동 소수점 연산(Floating-Point Arithmetic)에 대한 표준으로
실수를 부동 소수점이라는 방법으로 표현한다.
'부동(浮動)'이라는 용어는 혼란을 주기에 적당한 것인데(!)
사실은 '고정'에 반대되는 표현으로 '위치가 변경된다'는 의미이다.
(float의 번역 시 너무 단어의 의미에만 집착한 것 같다.
point (소수점)이 둥둥 떠다닌다는 의미로 사용한 말인데
차리리 '변동 소수점' 혹은 '가변 소수점' 등의 표현을 썼다면
조금 덜 혼란스럽지 않았을까 하는 생각도 든다.)

어쨌든 부동 소수점이란 소수점의 위치를 변경할 수 있다는 것인데
제한된 크기의 메모리 공간에서 표현할 수 있는 수의 범위를 키우기 위해 사용하며
대신 정확도가 희생될 수 있다(고 알고있다..;;)

부동 소수점 형식은 단정밀도(single precision), 배정밀도(double precision), 확장 배정밀도(extended double precision)가
있지만 크기의 차이일 뿐 본질적인 의미는 동일하므로 여기서는 단정밀도에 대해서만 다룬다.

단정밀도 형식은 32비트 크기이며 실수를 세 가지 부분으로 나누어 표현하는데 이는 각각,

  •  1비트의 부호 (0: 양수, 1: 음수)
  •  8비트의 자릿수(?) (exponent, 지수)
  •  23비트의 유효숫자 (significand 혹은 mantissa, 가수)

에 해당한다. (MSB부터 저장되는 순)

부호 비트는 너무나 당연한 것이므로 넘어가고
(보통 지수라고 부르는) 자릿수는 8비트이므로 총 256가지를 표현할 수 있지만
(부호없는 정수형이라고 가정할 때) 최소값인 0은 실제 숫자 0을 표현하기 위해 (뒤에 다시 설명한다.)
최대값인 255는 무한대 값을 표현하기 위해 예약되어 있다.
또한 자릿수가 증가하는 방향과(실제 숫자가 큰 경우) 자릿수가 감소하는 방향(실제 숫자가 작은 경우)을
모두 고려해야 하기 때문에 부호가 필요해지지만, 위에서 정의한 최대/최소값과의 일관적인 표현을 위해
부호없는 정수형으로 표현하는 것이 좋으므로(?) 실제 값에 일정한 상수를 더해서 저장한다.

즉, 8비트 중에서 실제로 사용할 수 있는 범위는 1부터 254까지이므로 (총 254개)
이를 음수/양수로 반반씩 나누어 할당하려면 127을 빼서 -126부터 127까지의 범위를 사용할 수 있고
저장할 때는 해당하는 수에 127을 더해서 저장하면 된다. (이 때 127은 바이어스(bias) (상수)라고 한다.)

알기 쉽게 10진수로 설명하자면,
123.456이라는 수의 경우 1.23456 x 10^2 혹은 123456 x 10^-3 등으로 표현이 가능한데
전자의 경우 지수값 '2'는 부동 소수점 형식으로 저장될 때 2 + 127 = 129로
후자의 경우 지수값 '-3'은 -3 + 127 = 124로 저장된다.

하지만 이렇듯 동일한 숫자를 여러 가지 형태로 표현할 수 있다는 것은
오히려 불필요한 혼란을 줄 수 있으므로 숫자를 오직 하나의 형태로만 표현할 수 있도록
다음과 같이 소수점 위에 유효숫자 중 한 자리 만 남기는 정규화 과정을 거친다. (normalize)

다시 10진수로 예를 들면, 다음과 같은 표현 만을 사용하도록 하는 것이다.
123.456 --> 1.23456 x 10^2
0.0001248 --> 1.248 x 10^-4
89.00000012 --> 8.900000012 x 10^1

하지만 실제로는 2진수로 저장되므로
부동 소수점 형식에서는 항상 유효숫자의 최상위 비트가 1이 되도록하여
소수점의 위치를 결정하게 된다.

예를 들어 43.25라는 10진수 숫자를 2진 부동 소수점 형식으로 나타내 보자.
우선 43은 이진수로 101011, 0.25는 0.01이므로
기본적인 표현 방식으로는 '101011.01'이 되겠다.
여기에 정규화를 하면 '1.0101101 x 2^5'와 같이 된다.
또 위에서 보았듯이 지수값 5에 바이어스 상수를 더하면 132가 되므로
실제로 저장될 지수값은 '10000100'이 될 것이다.

즉, 부호: 0, 지수: 10000100, 유효숫자: 10101101000000000000000 와 같이 된다.

한 가지 고려할 사항이 더 있는데,
정규화 과정을 거치면 항상 유효숫자의 최상위 비트가 1이 되므로
이를 저장하는 것은 낭비이다.
따라서 이를 생략하고 대신 이 비트를 활용하면
23비트로 2^24 범위의 유효숫자를 표현할 수 있게 된다.

따라서 이를 적용하면 43.25는 다음과 같이 표현될 것이다.
부호: 0, 지수: 10000100, 유효숫자: 01011010000000000000000
모두 연결하여 16진수로 표기하면 422d0000이 된다.