Среда, 2024-04-24
Сборник компьютерных технологий
Меню сайта
Категории раздела
My articles [30]
Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0
Главная » Статьи » My articles

GCC Fixed-Point Arithmetic

Размеры переменных можно подчерпнуть из таблицы  с https://gcc.gnu.org/wiki/avr-gcc

Type

sizeof

unsigned

signed

Note

_Fract

short

1

0.8

±.7

 

2

0.16

±.15

 

long

4

0.32

±.31

 

long long

8

0.64

±.63

GCC extension

_Accum

short

2

   8.8

   ±8.7

 

4

16.16

±16.15

 

long

8

32.32

±32.31

 

long long

8

16.48

±16.47

GCC extension

Функции, псевдонимы для сдвиговых операций (USACCUM_IBIT и др.) имеют следующие литеральные обозначения https://gcc.gnu.org/onlinedocs/gcc/Fixed-Point.html

  • hr’ or ‘HR’ for short _Fract and _Sat short _Fract
  • r’ or ‘R’ for _Fract and _Sat _Fract
  • lr’ or ‘LR’ for long _Fract and _Sat long _Fract
  • llr’ or ‘LLR’ for long long _Fract and _Sat long long _Fract
  • uhr’ or ‘UHR’ for unsigned short _Fract and _Sat unsigned short _Fract
  • ur’ or ‘UR’ for unsigned _Fract and _Sat unsigned _Fract
  • ulr’ or ‘ULR’ for unsigned long _Fract and _Sat unsigned long _Fract
  • ullr’ or ‘ULLR’ for unsigned long long _Fract and _Sat unsigned long long _Fract
  • hk’ or ‘HK’ for short _Accum and _Sat short _Accum
  • k’ or ‘K’ for _Accum and _Sat _Accum
  • lk’ or ‘LK’ for long _Accum and _Sat long _Accum
  • llk’ or ‘LLK’ for long long _Accum and _Sat long long _Accum
  • uhk’ or ‘UHK’ for unsigned short _Accum and _Sat unsigned short _Accum
  • uk’ or ‘UK’ for unsigned _Accum and _Sat unsigned _Accum
  • ulk’ or ‘ULK’ for unsigned long _Accum and _Sat unsigned long _Accum
  • ullk’ or ‘ULLK’ for unsigned long long _Accum and _Sat unsigned long long _Accum

Что такое _Sat? _Sat означает saturated, то есть насыщаемый. Если число достигло предела и после этого его попытались увеличить (инкрементировать, домножить), то значение не изменится. Без квалификатора _Sat поведение стандартом [ http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1169.pdf ] не определено, зависит от платформы. 

Отклонения от стандарта

double всегда 32 битный тип и является синонимом float

 

Функции bitsfx и fxbitss - преобразование полей бит

Заголовочный файл stdfix.h предоставляет функции для преобразования полей бит в тип с фиксированной точкой и обратно. В частности, эти функции полезны для преобразования между традиционными типами (uint_uhk_t, int_llr_t) и типами арифметики с фиксированной точкой (unsigned accum, short _Fract).

Для каждого типа с фиксированной точкой декларирован соответствующий целочисленный тип, который содержит достаточное количество бит, чтобы удержать в себе информацию типа с фиксированной точкой (см. таблицу выше).

Чтобы преобразовать тип с точкой дробного числа в поле бит, используйте семейство функций bitsfx. fx должен быть одним из сочетаний hr, r, lr, hk, k, lk, uhr, ur, ulr, uhk, uk или ulk. Так, для переменной unsigned short accum необходима функция bitsuhk и uhkbits, сдвиг с помощью имени USACCUM_IBIT.

Пример 1:   

    unsigned short accum myss =255.999uhk;
    uint_uhk_t left_val = bitsuhk( myss )>> USACCUM_IBIT;
    printf("%u.",left_val);

Выведет на экран целое значение myss, то есть 255. А bitsuhk( myss ) означает приведение к типу unsigned short всего числа 255.999uhk==65535

 

Набор функций семейства fxbits предоставляет побитное преобразование целого числа в тип числа с фиксированной точкой.

unsigned short accum right_side_raw = uhkbits(1);

 

Как выделить целую и дробную часть?

Когда нужно отобразить число с фиксированной запятой как набор десятичных цифр, действуют по алгоритму:
- сначала берут целую часть, и преобразуют её согласно Примеру 1.
- за целой частью ставят запятую (или точку).
- берут дробную часть. Она представляет из себя числитель и знаменатель. В качестве числителя используется то, что осталось после вычлинения целой части, знаменателем является два в степени количества бит, отведённое на хранение дробной части. В случае использования типа unsigned short accum это будет 8 бит, то есть знаменатель 256. Нужно из знаменателя сделать 10 или 100 или 1000 то есть 10^int. Домножим и числитель, и знаменатель  на константу. Например, 256x=1000, x=125/32. При операциях умножения и деления либо множитель x будет четным, либо делитель, либо они оба - и множитель, и делитель, будут нечетными (мы ведь формируем таким образом умножение на нецелое число). Мы также помним, что умножение и деление на эту 2^n заменяется логическим сдвигом влево и вправо соответственно.
- после этого полученное значение числителя переводим в набор десятичных цифр и приписываем их после запятой.

Чтобы пояснить эти "премудрости" возьмем все тот же пример - переведем дробное число с фиксированной запятой 100.11110b (== 0x9E) в символьное представление:
- целая часть у нас равна 100b, т. е. 4, выводим цифру 4
- выводим за целой частью дробную точку: 4.
- берем дробную часть 11110b. Она равна 30, т. е. наша дробь - числитель 30, а знаменатель 32. Наша задача - подобрать такое дробное число, чтобы при его умножении на знаменатель 32 получилось число, которое можно представить степенью десятки, причем какая была степень десятки, столько десятичных знаков после запятой и получим. Пусть надо получить 3 десятичных знака после запятой, т. е. знаменатель 32 приводим к 1000. Число x, на которое нужно домножить и числитель, и знаменатель, равно 32x=1000;x = 31.25. Отлично, но как умножить на дробное число, имея в распоряжении только целочисленную арифметику? Представи 31.25 в виде обыкновенной дроби: 125/4 = 31.25. На 125 умножаем как обычно, а делим на 4, сдвигая число на 2 бита вправо. Итак, 30 * 31.25 = (30 * 125) / 4 = 3750 / 4 = 937.5 тысячных. Заметьте, округлять при логическом сдвиге не получится, десятые улетят в никуда. Таким образом, (30 * 125)>>2=937. Чтобы сделать 938 можно попытаться умножать на число >125, но можно при реальном значении дроби .999 получить .1. Итак, первоначальная дробь 30/2^5 превратилась в дробь 937/1000.
- числитель 937 дописываем после запятой, получаем 4.937

Пример 2:

unsigned short accum myss =255.999uhk;
    
    uint_uhk_t left_val = bitsuhk( myss )>> USACCUM_IBIT;
    uint_uhk_t right_val = bitsuhk( myss ) & 0x00FF;
   
    printf(" %u.",left_val);
    printf("%03u ",(right_val*125)>>5);//(right_val*128)>>5 - формула выделяет тысячные доли числа; "03" - модификатор ширины: выводить минимум три цифры, если выводить нечего, забивать 3мя нулями
Ответ: 255.996   

 

Существуют специальные модификаторы для вывода чисел с фиксированной запятой в GCC (R, r, k и K). Но это не поддерживается avr-libc.

 

Вот хорошая обзорная статья по FPA в AVR с примерами http://geeklikemetoo.blogspot.ru/2016/10/fixed-point-math-with-avr-gcc.html

Сравнение FPA и Float point в AVR:

https://ucexperiment.wordpress.com/2015/03/31/avr-gcc-fixed-point-vs-floating-point-comparison/

В качестве ознакомительного чтения для немного иной архитектуры http://microsin.net/programming/dsp/visualdsp-using-native-fixed-point-types.html



Источник: http://infocenter.arm.com/help/topic/com.arm.doc.dai0033a/DAI0033A_fixedpoint_appsnote.pdf
Категория: My articles | Добавил: DungeonLords (2017-11-15)
Просмотров: 1025
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Форма входа
Поиск
Друзья сайта
  • Официальный блог
  • Сообщество uCoz
  • FAQ по системе
  • Инструкции для uCoz
  • Copyright Forcer, Inc © 2024
    Бесплатный конструктор сайтов - uCoz