Как мне преобразовать код C с плавающей запятой в код с фиксированной запятой?
-
09-10-2019 - |
Вопрос
У меня есть код на языке Си, который использует удвоения.Я хочу иметь возможность запускать код в DSP (TMS320).Но DSP не поддерживает удвоения, только числа с фиксированной запятой.Каков наилучший способ преобразовать код в формат с фиксированной запятой?Существует ли хорошая библиотека C для чисел с фиксированной запятой (реализованная в виде целых чисел)?
Решение
Ti предоставляет библиотеку фиксированной точки под названием «IQMath»:
http://focus.ti.com/lit/sw/sprc990/sprc990.pdf.
Преобразование включает в себя анализ вашего текущего кода - для каждой переменной вам нужно знать, какой диапазон он может удерживать, и какую точность им потребности. Тогда вы можете решить, какой тип хранится. IQMath предоставляет типы из Q30 с диапазоном +/- 2 и точность 0,0000000001 до Q1 с диапазоном ~ +/- 1 миллиона и точностью 0,5.
Для операций, которые могут переоценить диапазон переменных, вам нужно добавить проверки для переполнения и решать, как обрабатывать его - прикрепите его в Max, храните с другой шкалой, поднимите ошибку и т. Д.
На самом деле нет никакого способа преобразовать в фиксированную точку, не находящее глубокое понимание данного данных вашего процесса.
Другие советы
Следующий код определяет фиксированный тип, используя целые числа в качестве внутреннего представления. Дополнения и вычитания выполняются просто с +
и -
операторы. Умножение выполняется с использованием определенного 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. Есть много 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!");
}