Как преобразовать код с плавающей точкой 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!");
}