Как преобразовать код C с плавающей запятой в фиксированную точку? - PullRequest
13 голосов
/ 06 декабря 2010

У меня есть код C, который использует удваивается.Я хочу иметь возможность запустить код на DSP ( TMS320 ).Но DSP не поддерживает двойные числа, только числа с фиксированной запятой.Каков наилучший способ преобразования кода в фиксированную точку?Есть ли хорошая библиотека C для чисел с фиксированной точкой (реализована в виде целых чисел)?

Ответы [ 5 ]

12 голосов
/ 21 марта 2011

Следующий код определяет тип Fixed, используя целые числа в качестве внутреннего представления.Сложения и вычитания выполняются просто с помощью операторов + и -.Умножение выполняется с использованием определенного макроса MULT.

#include <stdio.h>
typedef int Fixed;

#define FRACT_BITS 16
#define FRACT_BITS_D2 8
#define FIXED_ONE (1 << FRACT_BITS)
#define INT2FIXED(x) ((x) << FRACT_BITS)
#define FLOAT2FIXED(x) ((int)((x) * (1 << FRACT_BITS))) 
#define FIXED2INT(x) ((x) >> FRACT_BITS)
#define FIXED2DOUBLE(x) (((double)(x)) / (1 << FRACT_BITS))
#define MULT(x, y) ( ((x) >> FRACT_BITS_D2) * ((y)>> FRACT_BITS_D2) )

Я использовал приведенный выше код для представления дробей в своем алгоритме обработки изображений.Это было быстрее, чем версия, которая использовала удваивается, и результаты были почти точно такими же.

8 голосов
/ 06 декабря 2010

TI предоставляет библиотеку с фиксированной запятой под названием «IQmath»:

http://focus.ti.com/lit/sw/sprc990/sprc990.pdf

Преобразование включает анализ текущего кода - для каждой переменной вам нужно знать, какой диапазон он может содержать,и какая точность ему нужна.Затем вы можете решить, в каком типе его хранить. IQMath предоставляет типы от q30 с диапазоном +/- 2 и точностью от 0,0000000001 до q1 с диапазоном ~ +/- 1 миллион и точностью 0,5.

Для операций, которые могут переполнять диапазон переменных, необходимо добавить проверки на переполнение и решить, как с этим справиться - закрепить его на максимуме, сохранить в другом масштабе, вызвать ошибку и т. Д.

Нет способа конвертировать в фиксированную точку без глубокого понимания потока данных вашего процесса.

5 голосов
/ 06 декабря 2010

Большинство наборов инструментов DSP включают в себя библиотеки для эмуляции с плавающей точкой в ​​программном обеспечении.Это будет медленно, но вы должны сначала создать свой код с поддержкой плавающей запятой, а затем профилировать, чтобы увидеть, есть ли несколько мест, которые вам нужно преобразовать в фиксированную точку, чтобы получить достаточную производительность.Вам также потребуется запустить программу с плавающей запятой, чтобы обеспечить сравнение при портировании с фиксированной запятой, чтобы убедиться, что вы ничего не потеряли в процессе.

2 голосов
/ 06 декабря 2010

Если код C использует удвоения очень редко / редко, то вы можете использовать библиотеку эмуляции с плавающей запятой, не заставляя код C работать в 10-100 раз медленнее.Если вы не хотите, чтобы производительность снижалась, и есть много операций с плавающей запятой, и вы знаете масштаб и точность, необходимые для каждой арифметической операции и операции сохранения для каждого реалистичного ввода, то вы можете преобразовать каждую арифметическую операцию вручнуюиспользуются масштабированные целочисленные типы данных и операции.Но анализ требований к точности, как правило, нетривиален для кода типа DSP.На эту тему имеется множество глав учебников по DSP и численным методам.

0 голосов
/ 06 декабря 2010

Есть несколько библиотек, которые могут сделать это для вас.Более вероятно, однако, PSP для вашего устройства должен включать в себя какую-то математическую библиотеку.Это должно быть задокументировано.Скорее всего, вам придется переписать некоторый код, потому что управляющие конструкции, которые вы используете при выполнении арифметики с плавающей точкой на основе примитивов, могут не иметь смысла, если вы используете API, предоставляемый вашим PSP.

Например -Вы можете конвертировать

double arraysum = 0.0;
for (int i = 0; i < arraylen; i++) 
{
    arraysum += array[i];
}

в

psp_decimal_t arraysum;
if (0 != psp_sum_elements(&array, arraylen, &arraysum))
{
    printf("error!");
}
...