Как преобразовать C-код с плавающей запятой в фиксированную точку?
У меня есть код C, который использует двойные слова. Я хочу иметь возможность запускать код на DSP (TMS320). Но DSP не поддерживает удвоения, только числа с фиксированной точкой. Каков наилучший способ преобразования кода в фиксированную точку? Есть ли хорошая библиотека C для чисел с фиксированной точкой (реализована как целые числа)?
Ответы
Ответ 1
TI предоставляет библиотеку с фиксированной точкой, называемую "IQmath":
http://focus.ti.com/lit/sw/sprc990/sprc990.pdf
Преобразование включает в себя анализ вашего текущего кода - для каждой переменной вам нужно знать, какой диапазон он может удерживать, и какую точность он нуждается. Затем вы можете решить, какой тип его хранить. IQMath предоставляет типы из q30 с диапазоном +/- 2 и точностью от 0,0000000001 до q1 с диапазоном ~ +/- 1 миллион и точностью 0,5.
Для операций, которые могут переполнять диапазон переменных, вам нужно добавить проверки для переполнения и решить, как с ним справиться - закрепите его в макс, сохраните с другим масштабом, поднимите ошибку и т.д.
На самом деле нет способа конвертировать в фиксированную точку, не получив глубокого понимания потока данных вашего процесса.
Ответ 2
Следующий код определяет тип 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) )
Я использовал приведенный выше код для представления фракций в моем алгоритме обработки изображений. Это было быстрее, чем версия, которая использовала парные, и результаты были почти точно такими же.
Ответ 3
Большинство инструментов DSP включают библиотеки для эмуляции с плавающей запятой в программном обеспечении. Это будет медленным, но вы должны сначала создать свой код с поддержкой с плавающей запятой, а затем профиль, чтобы узнать, есть ли всего несколько мест, которые вам нужно преобразовать в фиксированную точку, чтобы получить достаточную производительность. Кроме того, вам нужно будет иметь запущенные вещи с плавающей запятой, чтобы обеспечить сравнение по мере того, как вы переносите на фиксированную точку, чтобы убедиться, что вы ничего не потеряли в этом процессе.
Ответ 4
Если код C использует удвоение очень редко/редко, тогда вы можете использовать библиотеку эмуляции с плавающей запятой, не заставляя ваш C-код работать с 10X до 100X медленнее. Если вы не хотите, чтобы эта производительность попала, и есть много операций с плавающей запятой, и вы знаете масштаб и точность, необходимые для каждой операции арифметики и хранения для каждого реалистичного ввода, тогда вы можете преобразовать каждую арифметическую операцию вручную используются масштабированные целые типы данных и операции. Но анализ требований к точности является, вообще говоря, нетривиальным для кода типа DSP. Есть много глав учебника по DSP и числовым методам по этому вопросу.
Ответ 5
Есть несколько библиотек, которые могут сделать это для вас. Скорее всего, 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!");
}