Матричные операции для произвольных типов данных в C - PullRequest
2 голосов
/ 05 февраля 2020

Скажем, у меня есть функция, которая выполняет матричную операцию (например, транспонирование) для массива float:

void transpose(float *result, const float *input, int rows, int cols){

    int i,j;

    for(i = 0; i < rows; i++){
        for(j = 0; j < cols; j++){
            result[rows*j+i] = input[cols*i+j];
        }
    }

}

Эта функция будет работать для любого типа данных с размером sizeof(float). Может ли эта функция быть модифицирована для работы с массивами произвольного типа данных, или необходимо иметь отдельные функции для каждого типа данных разного размера (например, transpose_8, transpose_32, et c.)?

Ответы [ 2 ]

2 голосов
/ 05 февраля 2020

От комментарий от Евгений Sh. , вы можете передать void *, размер данных и размер типов, которые вы передаете, так что работает для всех типов.

Вы должны преобразовать их в char *, чтобы использовать арифметику указателей c.

Вот как это можно сделать:

void transpose(void *result, const void *input, int size, int rows, int cols)
{    
    int i, j;
    char *r = result;
    const char *i = input;

    for( i = 0; i < rows; i++ )
    {
        for( j = 0; j < cols; j++ )
        {
            memcpy(r + size * (rows * j + i), i + size * (cols * i + j), size);
        }
    }

}
1 голос
/ 05 февраля 2020

Можно ли изменить эту функцию для работы с массивами произвольного типа данных?

Да, вы можете передать обобщенный указатель c void * и размер одного элемента как параметр, именно так qsort() обрабатывает любой тип данных ( source ).

Вот рабочий пример:

void transpose(void *result, const void *input, size_t rows, size_t cols, size_t element_size) {
    unsigned char *input_ptr = (unsigned char *)input;
    unsigned char *result_ptr = (unsigned char *)result;
    size_t i, j;

    for(i = 0; i < rows; i++) {
        for(j = 0; j < cols; j++) {
            unsigned char *in = input_ptr + element_size * (cols * i + j);
            unsigned char *res = result_ptr + element_size * (rows * j + i);
            memcpy(res, in, element_size);
        }
    }
}

Вы также можете сделать это на месте, используя ту же технику замены, что и qsort():

void transpose_inplace(void *input, size_t n, size_t element_size) {
    unsigned char *input_ptr = (unsigned char *)input;
    size_t i, j;

    for(i = 0; i < n; i++) {
        for(j = 0; j < i; j++) {
            unsigned char *a = input_ptr + element_size * (n * i + j);
            unsigned char *b = input_ptr + element_size * (n * j + i);
            size_t size = element_size;

            while (size--) {
                unsigned char tmp = *a;
                *a++ = *b;
                *b++ = tmp;
            }
        }
    }
}

Я использую n здесь, поскольку для транспонирования на месте вам нужно квадратная матрица, где rows = cols = n.

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