Оптимизация: создание структуры, использующей разные типы данных - PullRequest
0 голосов
/ 09 мая 2020

Newb ie C программатор здесь. Я работаю над математической библиотекой в ​​C и сейчас реализую кое-что из линейной алгебры. Структура Matrix определяется следующим образом:

typedef struct {
    double** mat;
    int nRows;
    int nCols;
} Matrix ;

Я пытаюсь оптимизировать эту часть для развертывания atmel ATMega16A. У него около 1 КБ SRAM, а с двойным массивом я мог бы хранить в памяти только матрицу 8x8 с максимальным объемом памяти (или около 10 матриц 3x3 с некоторым пространством, оставшимся для других вычислений). Я понял, что в большинстве случаев мне не нужна точность double, и я могу обойтись использованием float.

Как правильно реализовать аналогичный struct с массивом float, который занимает меньше места в памяти?

В объектно-ориентированной среде правильным способом сделать это было бы создание абстрактного суперкласса Matrix и определение различных реализаций (например, MatrixDouble и MatrixFloat). Тогда один и тот же набор методов сможет выполнять операции в обеих реализациях. В этой библиотеке все методы в настоящее время возвращают double или Matrix* и принимают Matrix* аргументов, и я не хочу полностью переписывать эти методы и реализовывать по два метода для каждой процедуры, например double determinantDouble( MatrixDouble* mat ) и float determinantFloat( MatrixFloat* mat ).

Ответы [ 2 ]

1 голос
/ 10 мая 2020

Прежде всего, вы должны понять, что программирование микроконтроллера очень отличается от программирования P C. Микроконтроллеры ограничены практически всеми возможными способами, поэтому для их программирования требуется больше навыков и осторожности, особенно для устаревших 8-битных устройств. (Почему я рекомендую новичкам держаться подальше от 8-битных, это одни из самых сложных процессоров для правильного программирования в C.)

Вы должны отметить, что использовать типы с плавающей запятой - очень плохая идея. на 8-ми битных микроконтроллерах. У них нет FPU, поэтому вы заставляете компилятор подключать относительно огромную программную библиотеку с плавающей запятой, которая займет много памяти и времени выполнения.

Прочтите это, в частности

Когда использовать с плавающей запятой

Если ваш MCU имеет FPU, и вам действительно нужно выполнять сложные математические вычисления, тогда вы должны использовать плавающую точку . В противном случае вы не должны.

Обычно, если вы действительно нуждаетесь в математике с плавающей запятой, то вы выбрали неправильный MCU для задачи. Вы должны были выбрать Cortex M4 или больше со встроенным FPU.

Чтобы оптимизировать сам тип с плавающей запятой в зависимости от цели, один простой способ - это сделать что-то вроде:

typedef float float_t;

А затем изменить этот тип в соответствии с целью с помощью #ifdef переключателей компилятора.

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

Что-то вроде

typedef struct {
  float mat[MAX_X][MAX_Y];
  uint8_t nRows;
  uint8_t nCols;
} Matrix ;

Где nRows / nCols обозначают, какая часть матрицы фактически используется.

(Обратите внимание, что использование int во встроенной системе почти всегда неверно. Вместо этого используйте типы stdint.h, чтобы избежать подписанных типов и оптимизировать размер. 8-битные микроконтроллеры не любят 16-битные арифметики c и ненавидите 32-битную арифметику c, поэтому по возможности придерживайтесь uint8_t.)

Также возьмите за привычку использовать const корректность , то есть:

float_t determinantDouble (const Matrix* mat);
0 голосов
/ 09 мая 2020

Первое, что я бы порекомендовал, - это потерять указатель type **. Вместо этого просто укажите type * и выделите / сделайте так, чтобы он указывал на область памяти размером sizeof(type) * nRows * nCols. Наличие дополнительного уровня указателей означает, что вам необходимо хранить адреса nRows или nCols поверх ваших фактических данных.

Чтобы сделать матрицу более «типичной c» в C, вы могли бы определить некоторые макросы:

#define Matrix_Type(type) \
    typedef struct {      \
        type *data;       \
        int nRows;        \
        int nCols;        \
    } Matrix_##type

Затем:

 Matrix(float);

Предоставит вам определение типа для матрицы чисел с плавающей запятой с именем Matrix_float. Но вам придется переработать всю вашу библиотеку, чтобы вместо функций была куча макросов. C не имеет встроенной универсальности типов, поэтому вам придется создавать его самостоятельно ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...