【问题标题】:Matrix operations for arbitrary data types in CC中任意数据类型的矩阵运算
【发布时间】:2020-02-04 21:20:29
【问题描述】:

假设我有一些函数可以对 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_8transpose_32 等)设置单独的函数?

【问题讨论】:

  • 传递 void 指针,传递数据大小,使用大小计算指针偏移量并使用 memcpy 而不是赋值。
  • @EugeneSh。谢谢,我知道我缺少一些明显的东西。将此作为答案,我会接受。
  • 虽然可以实现通用矩阵转置例程,但矩阵转置是一个臭名昭著的性能问题,如果矩阵大小很大,则可以预期通用例程的性能会受到很大影响。在这种情况下,尝试通用化将是一个坏主意。

标签: c matrix


【解决方案1】:

a commentEugene Sh.,您可以传递void *、数据的大小以及您要传递的类型的大小,因此它适用于所有类型。

不过,您必须将它们转换为 char *,这样才能使用指针算法。

您可以这样做:

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);
        }
    }

}

【讨论】:

    【解决方案2】:

    可以修改此函数以使用任意数据类型的数组吗?

    是的,您可以传递一个通用的 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

    【讨论】:

    • Transpose 是作为示例给出的。这是一个具体的解决方案。
    • @PaulOgilvie 这正是 OP 所要求的。该示例仅用于展示如何实现通用功能。第二个例子是为了进一步解释如何在需要时实现交换而不是仅仅复制。我真的不明白这里有什么问题。
    • 但是交换是转置操作的一部分。这就是为什么它被称为“转置”。您的解决方案不支持任何其他矩阵运算。对于必须支持的任何矩阵运算,对任何类型的矩阵进行运算的通用解决方案是什么?
    • @PaulOgilvie 更仔细地阅读了函数签名。 OP 帖子中给出的功能不需要任何类型的交换。这就是为什么单个memcpy() 就足以完成这项工作的原因。但是,如果执行涉及就地修改的操作,则需要执行适当的交换。这就是我写这两个函数的原因。
    • @PaulOgilvie 按照您的逻辑,其他答案也不应该是好的。我的解决方案作为如何转换 OP 代码的示例给出。显然不可能实现“泛型矩阵运算”功能。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-16
    相关资源
    最近更新 更多