Как преобразовать код C с плавающей запятой в фиксированную точку?

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

5 ответов

Решение

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

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

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

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

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

Следующий код определяет тип 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) )

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

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

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

Есть несколько библиотек, которые могут сделать это для вас. Скорее всего, 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!");
}
Другие вопросы по тегам