矩阵乘法算法的C代码输出不一致

kmb7vmvb  于 2022-12-03  发布在  其他
关注(0)|答案(1)|浏览(132)

我编写了以下代码来执行一个简单的矩阵乘法。

#include <stdio.h>

void op2(float *a_vec, int m, int n, int p, float *b_vec, float *c_vec){
    float (*a)[n] = (float(*)[n]) a_vec;
    float (*b)[p] = (float(*)[p]) b_vec;
    float (*c)[p] = (float(*)[p]) c_vec;
    int i, j, k;

    for (i = 0; i<m; i++){
        for(j=0; j<p; j++){
            for(k=0; k<n; k++){
                c[i][j] += a[i][k] * b[k][j];
            }
            printf("%.1f ", c[i][j]);
        }
        printf("\n");
    }
    
}

int main(void){
    float *aVec;
    float *bVec;
    float *cVec;
    int m = 2;
    int n = 3;
    int p = 2;

    float a[6] = {
                1,3,1,
                2,2,2
                };

    aVec = &a[0];

    float b[6] = {
        1,3,
        1,2,
        2,2
        };

    bVec = &b[0];
    float c[4];
    cVec = &c[0];

    op2(aVec, m, n, p, bVec, cVec);
}

生成的矢量(打印到输出)应为6.0 11.0 8.0 14.0
事实上...大多数时候。
然而,有时并不是这样。有时数组的第一个值会不正确。最常见的是5.7或5.8 5.8 11.0 8.0 14.0
我的问题是,我在这里做了什么,导致了这种不一致?我对C很陌生,我最好的猜测是,也许我遗漏了一些与数组索引有关的东西,也许我跑过了数组的结尾?但是我不明白,如果它有相同的输入,它怎么会不一致,所以也许我遗漏了一些与指针有关的东西?
尝试过:在循环外声明数组变量,更改输入数组中的值。

gojuced7

gojuced71#

只有当c矩阵初始化为0时,循环中才有c[i][j] += a[i][k] * b[k][j];。但是,main中的c数组float c[4];声明时没有初始化器,所以它包含垃圾,当你将乘法结果相加时,会产生更多的垃圾。
valgrind内存检查工具发现了这个bug。像这样的工具对于C调试来说是无价的,当你遇到bug时,应该首先尝试一下。AddressSanitizer(-fsanitize=address)和UBSan(-fsanitize=undefined)在愚者和clang中都有,它们也很好,但是它们碰巧没有发现这个bug。
这个特殊的问题可以通过定义float c[4] = {0.0};来解决。(只要你初始化了数组中的至少一个元素,其余的所有元素都会自动初始化为零。)

相关问题