Как преобразовать код с плавающей точкой 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 работать от 10X до 100X медленнее. Если вы не хотите, чтобы эта производительность ударила, и есть много операций с плавающей запятой, и вы знаете масштаб и точность, необходимые для каждой арифметической операции и операции хранения для каждого реалистичного ввода, то вы можете преобразовать каждую арифметическую операцию вручную в используемые масштабированные целочисленные типы данных и операции. Но анализ требований к точности, как правило, нетривиален для кода типа 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!");
}