SSE循环处理双精度数组点积结果异常,预期值与实际值不符
MASM64双精度数组点积+平方根计算错误修复
代码中的核心问题
- XMM寄存器未初始化:xmm3在第一次使用前没有清零,初始值是随机垃圾数据,直接
addpd xmm3, xmm1会导致结果混入错误值。 - 循环地址未动态偏移:每次循环都固定加载
[array1+8]和[array2+8],没有用指针随循环推进移动,导致反复处理数组的第2、3个元素,而非遍历整个数组。 - 循环次数完全错误:数组有7个双精度元素(每个占8字节),
mulpd一次处理2个元素,实际只需要3次循环处理前6个元素,再单独处理最后1个,设置7次循环完全不符合逻辑。 - 点积求和逻辑错误:点积要求所有对应元素相乘后累加为一个标量,但你用
addpd只是对两组双精度元素分别并行相加,最后没有将XMM寄存器里的所有元素合并成单个总和就直接开平方,得到的是两个独立值的平方根,而非点积的平方根。
修复后的代码
include /masm64/include64/masm64rt.inc INCLUDELIB MSVCRT option casemap:none .data array1 dq 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0 array2 dq 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0 res dq 0.0 tit1 db "Result of using the SSE", 0 buf BYTE 260 dup(?) bufp QWORD buf, 0 array_len dq 7 ; 数组元素个数 .code entry_point proc ; 初始化累加寄存器xmm3为0,用于存储并行相加的结果 xorpd xmm3, xmm3 ; 初始化数组指针 mov rsi, offset array1 mov rdi, offset array2 ; 计算需要处理的2元素组数量:7//2=3组,剩余1个元素 mov rcx, array_len shr rcx, 1 ; 等价于rcx = rcx / 2 loop1: ; 加载一组2个双精度元素 movupd xmm1, [rsi] movupd xmm2, [rdi] ; 对应元素相乘 mulpd xmm1, xmm2 ; 并行累加到xmm3 addpd xmm3, xmm1 ; 指针向后移动16字节(2个双精度元素) add rsi, 16 add rdi, 16 loop loop1 ; 处理剩余的单个元素(如果数组长度是奇数) test array_len, 1 jz skip_single ; 加载最后一个元素相乘 movsd xmm1, [rsi] movsd xmm2, [rdi] mulsd xmm1, xmm2 ; 将单个结果累加到xmm3的低64位 addsd xmm3, xmm1 skip_single: ; 将xmm3中的两个并行结果累加为一个标量 movhlps xmm1, xmm3 ; 将xmm3的高64位移动到xmm1的低64位 addsd xmm3, xmm1 ; xmm3低64位 = 低64位 + 高64位,得到总点积 ; 对总点积求平方根 sqrtsd xmm1, xmm3 ; 存储结果并显示 movsd res, xmm1 invoke fptoa, res, bufp invoke MessageBox, 0, bufp, addr tit1, MB_OK invoke ExitProcess, 0 entry_point endp end
关键修复说明
- 寄存器初始化:用
xorpd xmm3, xmm3清零累加寄存器,避免垃圾数据干扰。 - 动态指针遍历:用rsi/rdi作为数组指针,每次循环后偏移16字节,实现数组遍历。
- 分组+剩余元素处理:先处理所有2元素组,再单独处理奇数长度下的剩余元素,确保所有元素都被计算。
- 并行结果合并:用
movhlps将xmm3的高64位值移到xmm1低64位,再用addsd将两个值累加为单个点积,最后对这个标量开平方。
内容的提问来源于stack exchange,提问作者hyen
相关产品推荐
相关产品推荐

