본문 바로가기
Audio Processing

신호처리와 숫자 표현(3)-고정 소수점, 부동 소수점의 변환

by gigasound 2021. 8. 17.


고정 소수점과 부동 소수점의 변환

신호처리에서 실수는 고정 소수점 방식과 부동 소수점 방식으로 기록됩니다.

고정 소수점 방식은 메모리 비트를 그대로 읽으면 실수로 표시되기 때문에 하드웨어 매우 유리한 방식입니다. 이에 반해 부동 소수점 방식은 코딩 과정에 유리합니다.

이 두 표현 관계는 신호처리 과정에서 상호 변환해서 사용하기도 합니다. 특히 필터의 계수값을 구할때 고정 소수점 방식으로 구하지 않습니다. 부동 소수점이 일반적인 수학 연산 표현에 더 적합하기 때문입니다. 그러니 부동 소수점으로 구한 값을 고정 소수점으로 변환해서 주로 사용하게 됩니다. 

이 글에서는 두 표현 방법 간에 변환 방법을 알아보겠습니다.


실수의 고정 소수점$(N_{fixed})$ 표현 

먼저 다음 공식을 이용해서 실수 R을 Qm.n 형식으로 $N_{fixed}$를 구합니다. 여기서 Round()는 실수를 정수로 변환하는 함수입니다. 일반적으로 C와 같은 신호처리 언어에 포함되어 있습니다.

그리고 메모리에 기록된 내용을 옮겨와서 기록합니다.

$$N_{fixed}=Round(R\cdot2^{n})$$

메모리 내용을 읽어오는 함수는 다음과 같습니다.

#define FRAG_SIZE (23) //- 고정 소수점의 소수부분

int32_t float_to_fixed(float x) {
	float y = x * (float)((int32_t)1<< FRAG_SIZE);
	return (int32_t)roundf(y);
}

결과는 32bit입니다. 이를 메모리 형태로 보고나 기록하고 싶으면 다음과 같이 하면 됩니다. 즉 R=2.33의 부동 소수점 표현을 버퍼로 기록하고 이를 외부 장비로 보내거나 기록해서 활용할 수 있습니다. 이는 매우 중요한 내용입니다. 

float R = 2.33f;
int32_t fixed = float_to_fixed(R);
uint8_t* buf = (int8_t*)calloc(BUF_SIZE, sizeof(uint8_t));
buf[0] = (fixed >> 24) & 0xff;
buf[1] = (fixed >> 16) & 0xff;
buf[2] = (fixed >> 8) & 0xff;
buf[3] = fixed & 0xff;

고정 소수점의 부동 소수점 표현

위의 내용과 반대로 고정 소수점 형태로 입력되는 버퍼의 내용을 부동 소수점으로 변환해서 신호처리에 활용하는 방법은 아래와 같습니다. 여기서 (float)는 C언어의 형식 변환자입니다. 

$$R=(float)(N_{fixed}/2^{n})$$

buf[4]에 기록된 고정 소수점은 다음과 같이 변환됩니다.

float fixed_to_float(uint8_t* buff) {
	int32_t x = 0;
	x |= (uint32_t)buff[0] << 24;
	x |= (uint32_t)buff[1] << 16;
	x |= (uint32_t)buff[2] << 8;
	x |= (uint32_t)buff[3];
	return ((float)x / ((uint32_t)1 << FRAG_SIZE));
}

그린데 두 변환 과정에서 실수 결과 다소 다른 값을 가질 수 있습니다. 이는 실수를 부동 또는 고정 소수점 방식으로 변환하면서 오류를 가지기도 하고 두 표현 방식의 변환 과정에서도 발생하기 때문입니다. 이는 신호처리 과정에서 오류를 일으킬 수도 있습니다.

다음 글에서 고정소수점과 부동 소수점간의 변환 방법을 알아 보겠습니다. 

https://medialink.tistory.com/72?category=958130 


부동 소수점 연산의 오류

컴퓨터 연산은 우리가 기대하는 것과 같이 정밀하지 못합니다. 이유는 숫자를 비트로 표현하면서 실제 값을 완전히 반형하지 못한 표현 형태를 사용하기 때문입니다. 다른 글의 예에서 0.33이 유한 소수임에도 불구하고 부동 소수점으로 표현하면 무한한 비트 표현이 필요함을 보인적이 있습니다.

https://medialink.tistory.com/71?category=958130 

이번엔 컴퓨터에서 연산하면서 살펴보겠습니다.

0.1을 100번 더하면 10이 나와야 하죠. 이를 아래와 같이 C언어로 작성해 보겠습니다.

 #include <stdio.h>

int main(void) {
	printf("Start\r\n");
	//-부동 소수점으로 x=0.1f 선언
	float x = 0.1f;
	float y = 0.0f;
	//- x를 100번 더해서 y에 기록
	for (int i = 0; i < 100; i++) { y += x; }
	//- 연산 결과를 출력
	printf("y=%f\r\n", y);
	return getchar();
}

그런데 출력 결과는 10.000002로 나옵니다. 헉! 매우 단순한 연산인데도 한눈에 결과 오류를 확인 할 수있습니다. 컴퓨터 연산 결과를 믿지 마세요. 


광고좀 꾹 눌러주시면 고맙겠습니다. 


위의 내용을 참조용으로만 사용해주세요. 무단 도용이나 무단 복제는 불허합니다.

기타 문의 사항은 gigasound@naver.com에 남겨 주시면 고맙겠습니다.