Формат Q и фиксированная точка
Формат Q — способ хранить дробные числа в обычных целых переменных: целое число считается делённым на степень двойки. Так считают на микроконтроллерах без блока плавающей точки — быстро и с предсказуемой точностью.
Обновлено Редакция GAW
Формат Q (Qm.n) — способ записи дробных чисел с фиксированной точкой (fixed-point): знаковое целое из 1 + m + n бит интерпретируется как целое, делённое на 2n. Здесь n — число бит дробной части, m — целой. Сложение и вычитание выполняются обычными целочисленными командами, а положение запятой программист держит в уме.
Распространённые форматы
| Формат | Тип | Диапазон | Шаг |
|---|---|---|---|
| Q7 (1.7) | int8_t | −1 … 0,9922 | 2−7 ≈ 0,0078 |
| Q15 (1.15) | int16_t | −1 … 0,99997 | 2−15 ≈ 3,05 · 10−5 |
| Q31 (1.31) | int32_t | −1 … 1 − 2−31 | 2−31 ≈ 4,66 · 10−10 |
| Q16.16 | int32_t | −32 768 … 32 767,99998 | 2−16 ≈ 1,53 · 10−5 |
Перевод: целое = round(значение · 2n), значение = целое / 2n. Например, 0,3 в Q15 — round(0,3 · 32 768) = 9830, а обратно 9830 / 32 768 = 0,29999: погрешность меньше половины шага. Перевод в обе стороны с hex и диапазоном формата считает калькулятор формата Q. Обозначения 1.7, 1.15 и 1.31 использует библиотека CMSIS-DSP для типов q7_t, q15_t и q31_t; стандарт Embedded C (TR 18037) вводит для них типы _Fract и _Accum, которые поддерживает avr-gcc.
Арифметика
Сложение двух чисел одного формата — обычное сложение целых, но результат может выйти за диапазон, и тогда нужно насыщение. Умножение выполняют в удвоенной разрядности и сдвигают результат вправо на n бит:
Сдвиги, маски и продвижение типов, на которых строится такая арифметика, разобраны в статье о битовых операциях, а умножение с округлением, деление, насыщение и примеры — в статье «Фиксированная точка». Типы целых и их размеры на AVR и ARM — в статье «C для микроконтроллеров». Код АЦП — по сути то же число с фиксированной точкой: доля опорного напряжения с шагом в один младший разряд, 2−N.
Частые вопросы
Что такое формат Q15?
16-битное знаковое целое, в котором 15 младших бит — дробная часть. Значение равно целому, делённому на 2^15 = 32 768, поэтому диапазон — от −1 до 1 − 2^−15 ≈ 0,99997, а шаг — около 3,05 · 10^−5. В CMSIS-DSP это тип q15_t, в GCC — _Fract.
Как перемножить два числа Q15?
Перемножить как 32-битные целые и сдвинуть произведение вправо на 15 бит: (int16_t)(((int32_t)a * b) >> 15). Для округления к ближайшему перед сдвигом прибавляют 1 << 14. Произведение −1 на −1 даёт +1, которое в Q15 не помещается, — этот случай обрабатывают насыщением.
Когда фиксированная точка лучше float?
На ядрах без блока плавающей точки — AVR, Cortex-M0, M0+, M3, — где float считается программно и медленно, и там, где нужна одинаковая абсолютная точность во всём диапазоне: в цифровых фильтрах, регуляторах, обработке сигналов АЦП. Плата за это — нужно самому следить за диапазоном и переполнением.
Источники
- ISO/IEC TR 18037 (Embedded C), WG14 N1169, 2006 — 4.1 — типы _Fract и _Accum, диапазон fract от −1 до 1, форматы s.7, s.15; 4.1.3 — переполнение и насыщение
- Arm. CMSIS-DSP: arm_math_types.h (github.com/ARM-software/CMSIS-DSP) — q7_t — int8_t в формате 1.7, q15_t — int16_t в формате 1.15, q31_t — int32_t в формате 1.31
- GCC Wiki: avr-gcc — Fixed-Point Support; GCC Manual: Fixed-Point Types — avr-gcc с версии 4.8: short _Fract s.7, _Fract s.15, long _Fract s.31, _Accum s16.15
Нашли ошибку?
Смотрите также
- Фиксированная точкаФормат Q, умножение со сдвигом, округление, насыщение, q15 и _Fract
- Формат Q: Q15, Q31, IQmathЧисло ↔ целое в Qn, hex, округление, насыщение, диапазон и шаг, код на C
- Битовые операции в CМаски, сдвиги, установка и проверка битов, ловушки стандарта C
- C для микроконтроллеровТипы, stdint, volatile, атомарность, регистры, константы во Flash
- Младший разряд (LSB)Шаг квантования АЦП VREF / 2^N и ошибка ±½ LSB