노트 / 자료구조와 알고리즘
고정소수점 연산: 정수로 소수 다루기
FPU가 없는 MCU에서 소수를 빠르게 계산하는 Q 포맷. 스케일, 곱셈 후 시프트, 포화 처리를 정리했습니다.
Cortex-M0나 8비트 MCU에는 부동소수점 연산기(FPU)가 없어서 float 곱셈 하나가 수십 클럭 걸립니다. 고정소수점은 정수에 "소수점이 여기 있다"는 약속을 더해 정수 연산 속도로 소수를 다룹니다.
Q 포맷
Q15는 16비트 정수에서 아래 15비트를 소수부로 씁니다. 실제 값 = 정수값 / 2¹⁵ 이라서 -1.0 이상 1.0 미만을 표현합니다.
| 실제 값 | Q15 정수 |
|---|---|
| 0.5 | 16384 |
| -0.25 | -8192 |
| 0.999 | 32735 |
곱셈
Q15 두 개를 곱하면 Q30이 되므로 15비트 오른쪽으로 밀어 되돌립니다. 중간 결과는 32비트에 담습니다.
int16_t q15_mul(int16_t a, int16_t b) {
int32_t r = (int32_t)a * b;
return (int16_t)(r >> 15);
}
주의할 점
- 오버플로: 더한 결과가 범위를 넘으면 부호가 뒤집힙니다. 최대값에서 멈추게 하는 포화 연산을 씁니다.
- 정밀도: 작은 값을 여러 번 곱하면 아래 비트가 사라집니다. 적분기처럼 계속 더하는 변수는 비트를 넉넉히 줍니다.
- 스케일 문서화: 변수마다 어떤 Q 포맷인지 이름이나 주석에 남겨야 나중에 섞어 쓰는 실수를 막습니다.
Cortex-M4처럼 FPU가 있으면 float이 오히려 편하고 빠를 수 있으니, 대상 MCU를 보고 고릅니다.