【发布时间】:2021-08-18 04:01:54
【问题描述】:
我不确定在哪里问这个问题的最佳地点,但我目前正在使用 ARM 内部函数并遵循本指南:https://developer.arm.com/documentation/102467/0100/Matrix-multiplication-example
但是,那里的代码是假设数组以列优先顺序存储的。我一直认为 C 数组是按行存储的。他们为什么这么认为?
编辑: 例如,如果不是这样:
void matrix_multiply_c(float32_t *A, float32_t *B, float32_t *C, uint32_t n, uint32_t m, uint32_t k) {
for (int i_idx=0; i_idx < n; i_idx++) {
for (int j_idx=0; j_idx < m; j_idx++) {
for (int k_idx=0; k_idx < k; k_idx++) {
C[n*j_idx + i_idx] += A[n*k_idx + i_idx]*B[k*j_idx + k_idx];
}
}
}
}
他们这样做了:
void matrix_multiply_c(float32_t *A, float32_t *B, float32_t *C, uint32_t n, uint32_t m, uint32_t k) {
for (int i_idx=0; i_idx < n; i_idx++) {
for (int k_idx=0; k_idx < k; k_idx++) {
for (int j_idx=0; j_idx < m; j_idx++) {
C[n*j_idx + i_idx] += A[n*k_idx + i_idx]*B[k*j_idx + k_idx];
}
}
}
}
由于按 C[0]、C[1]、C[2]、C[3] 的顺序访问 C 的空间局部性,而不是按 C[0]、C[2 的顺序访问 C,代码将运行得更快]、C[1]、C[3](其中 C[0]、C[1]、C[2]、C[3] 在内存中是连续的)。
【问题讨论】:
-
地址空间是线性的,不是二维的,没有“行”和“列”——有些元素就像更远和更近。
Why did they assume this?We have assumed a column-major layout of the matrices in memory. That is, an n x m matrix M is represented as an array M_array where Mij = M_array[n*j + i].他们可以做到n*j_idx + i_idx或j_idx + n*i_idx。什么是列或行,只是您/他们的解释,您可以翻转术语并没问题。 -
@KamilCuk 好的,我想我明白你的意思了。所以我想我的问题应该是为什么他们决定低效地实现矩阵乘法而不是连续访问数组?
-
matrix multiply inefficiently我没有看到更有效的方法......你是什么意思?not accessing the arrays contiguously因为它是一个“矩阵乘法示例”——所以他们访问数组就好像它是一个矩阵一样,并且他们以特定的方式对其进行特定的操作。编程语言是一种抽象——总的来说,它都是机器指令。这只是一个抽象——当Mij = ... -
@KamilCuk 通过在编辑中在 j 和 k 之间进行循环交换更有效
-
您发布的代码无效 -
C[n*j_idx + i_idx]未初始化时使用,j_idx = 1时使用,然后它会被归零。我首先会做memset(C, 0, ...)。不管怎样,页面上写着“矩阵乘法示例”——当然这并不是为了高效,而是展示它是如何工作的。
标签: c optimization matrix-multiplication neon row-major-order