You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Intrinsics实现矩阵乘法加载矩阵错误结果全0如何解决

问题产生原因
  • 直接原因:循环变量k定义在所有循环外部,首次内层k循环执行完成后,k的值会大于等于N-3,后续进入新的j循环时,k < N-3的条件不成立,内层计算逻辑完全不会执行,累加寄存器r始终保持初始的0值,最终写入result数组的结果自然全为0。
  • 累加逻辑错误:累加寄存器r仅在所有循环开始前清零一次,即便解决了循环变量的问题,每次计算新的result[i][j]元素时也会累加之前的计算结果,导致数值错误。
  • 矩阵乘原理性错误:
    1. _mm_mul_ps是向量逐元素相乘的指令,现有逻辑直接将mat1行的4个元素与mat2加载的4个元素逐元素乘加,并没有完成矩阵乘法要求的行与列的点积计算;且&mat2[k][j]加载的是mat2第k行的连续4个元素,不是第j列的4个元素,完全不符合矩阵乘法的行列运算规则。
    2. 收尾循环的计算逻辑错误,现有代码写为mat1[i][j] * mat2[k][j],正确的矩阵乘运算应该是mat1[i][k] * mat2[k][j]。
  • 内存对齐风险:_mm_load_ps要求加载的内存地址必须16字节对齐,如果你的mat1、mat2数组没有做对齐处理,加载操作会触发未定义行为,也可能导致结果异常。
修复方案
  1. 调整循环变量的作用域,将i、j、k放在对应循环的声明位置,避免循环变量残留值影响后续执行逻辑。
  2. 将累加寄存器r的清零操作移动到每个result[i][j]元素计算之前,也就是j循环内部、内层k循环的外部,保证每次计算新元素的累加都是从0开始。
  3. 修正矩阵乘法的运算逻辑:可以先将mat2做转置处理,转置后原mat2的列变为转置矩阵的行,就可以直接用向量加载指令读取原矩阵的列元素;之后可以用_mm_dp_ps指令直接计算两个向量的点积,或是手动通过向量移位加操作计算点积。
  4. 如果你无法保证矩阵内存16字节对齐,可以改用_mm_loadu_ps执行非对齐加载,避免对齐限制导致的异常。
  5. 修正收尾循环的计算逻辑。

修复后参考代码

// 提前对mat2做转置,存在mat2_T中,mat2_T[j][k] = mat2[k][j]
for (int i = 0; i < N; ++i)
{
    for (int j = 0; j < N; j += 4)
    {
        __m128 r = _mm_setzero_ps();
        int k = 0;
        // 向量计算部分
        for (; k < N - 3; k += 4)
        {
            __m128 mat1_v = _mm_loadu_ps(&mat1[i][k]);
            __m128 mat2_v = _mm_loadu_ps(&mat2_T[j][k]);
            // 计算4个元素的点积,结果存到r的所有四个位置
            __m128 dp = _mm_dp_ps(mat1_v, mat2_v, 0xF1);
            r = _mm_add_ps(r, dp);
        }
        float sum = r.m128_f32[0];
        // 收尾计算剩余不足4个的元素
        for (; k < N; k++)
        {
            sum += mat1[i][k] * mat2[k][j];
        }
        // 写入结果,这里示例j每次步长4,j+1、j+2、j+3的计算逻辑和上面一致,可自行补充
        result[i][j] = sum;
    }
}

注:如果你的编译环境不支持_mm_dp_ps(SSE4.1指令集),可以自行用向量移位相加的方式计算点积。


内容的提问来源于stack exchange,提问作者Leon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 17:57:00