5.7 汇编语言:汇编高效乘法运算 您所在的位置:网站首页 汇编语言查看结果 5.7 汇编语言:汇编高效乘法运算

5.7 汇编语言:汇编高效乘法运算

2024-06-05 18:09| 来源: 网络整理| 查看: 265

乘法指令是一种在CPU中实现的基本算术操作,用于计算两个数的乘积。在汇编语言中,乘法指令通常是通过mul(无符号乘法)和imul(有符号乘法)这两个指令实现的。由于乘法指令在执行时所消耗的时钟周期较多,所以编译器在优化代码时通常会尝试将乘法操作转换为更高效的加法、和移位操作。

对于较小的数,编译器可能会选择将乘法操作直接转换为加法操作。例如,将表达式a * b转换为a + a + ... + a(b次相加)的形式。这种方式可以通过循环展开、代码向量化等技术来优化。

对于较大的数,编译器可能会使用位移和移位操作来代替乘法。例如,将表达式a * b转换为a 计算 eax * 3 - 7 lea edx,dword ptr ds:[eax * 2] ; edx = eax * 2 add edx,eax ; edx = edx + eax sub edx,7 ; edx = edx - 7 invoke crt_printf,addr szFmt,edx ; edx = eax * 3 - 7 invoke ExitProcess,0 main ENDP END main 7.5 使用SHL计算无符号乘法

通过使用逻辑左移同样可以实现2的次幂的高速乘法运算,但逻辑左移只能用于计算无符号乘法,且只能计算被乘数是2的次方的算式。

计算时我们需要参考次方表,这里我列举出几个常用的次方数值:

次方表: 1=>2 2=>4 3=>8 4=>16 5=>32 6=>64 7=>128 次方表: 8=>256 9=>512 10=>1024 11=>2048 12=>4096 13=>8192 14=>16384

假设 eax=3 计算 eax * 8 + 10 的结果,拆分过程如下:

1.计算 shl eax,3 这就相当于计算 eax = eax * 2 ^(次方) 3 其公式相当于计算 eax = eax * 8 2.计算 add eax,10 这就相当于计算 eax = (eax * 8) + 10 3.最终即可得到计算结果也就是3*8+10得到34

通过使用逻辑左移,我们可以实现快速无符号乘法运算,如下代码是效率最高的一种。

.data x DWORD ? szFmt BYTE '计算结果: %d',0dh,0ah,0 .code main PROC mov dword ptr ds:[x],3 ; 计算 eax = eax * 2 ^ 1 相当于计算 eax * 2 mov eax,dword ptr ds:[x] shl eax,1 invoke crt_printf,addr szFmt,eax ; 计算 eax = eax * 2 ^ 2 相当于计算 eax * 4 mov eax,dword ptr ds:[x] shl eax,2 invoke crt_printf,addr szFmt,eax ; 计算 eax = eax * 2 ^ 3 相当于计算 eax * 8 mov eax,dword ptr ds:[x] shl eax,3 add eax,10 invoke crt_printf,addr szFmt,eax invoke ExitProcess,0 main ENDP END main 7.6 使用SAL计算有符号乘法

通过使用算数左移同样可以实现2的次幂的高速乘法运算,与逻辑左移不同,算术左移只能计算有符号乘法,且只能计算被乘数是2的次方的算式。

计算时我们需要参考次方表,这里我列举出几个常用的次方数值:

次方表: 1=>2 2=>4 3=>8 4=>16 5=>32 6=>64 7=>128 次方表: 8=>256 9=>512 10=>1024 11=>2048 12=>4096 13=>8192 14=>16384

假设 eax=-5,ebx=3 计算 (eax * 8) + (ebx * 4) 的结果,拆分过程如下:

1.计算 sal eax,3 这就相当于计算 eax = (eax * 2 ^ 3 ) 其公式相当于计算 eax = eax * 8 结果是一个有符号数 2.计算 shl ebx,2 这就相当于计算 ebx = (ebx * 2 ^2) 其公式相当于计算 ebx = ebx * 4 结果是一个无符号数 3.最终将有符号与无符号数通过 add eax,ebx 相加,即可得到(eax * 8) + (ebx * 4)的最终结果-28

如下是通过算数左移,实现2的次幂的高速乘法运算,我们可以将算数运算与逻辑运算相加通过此方式提高运算效率。

.data x DWORD ? y DWORD ? szFmt BYTE '计算结果: %d',0dh,0ah,0 .code main PROC mov dword ptr ds:[x],-5 mov dword ptr ds:[y],3 ; 计算 eax = eax * 2 ^ 1 相当于计算 eax * 2 mov eax,dword ptr ds:[x] sal eax,1 invoke crt_printf,addr szFmt,eax ; 计算 eax = eax * 2 ^ 2 相当于计算 eax * 4 mov eax,dword ptr ds:[x] sal eax,2 invoke crt_printf,addr szFmt,eax ; 计算 eax = (eax * 2 ^ 3 ) + (ebx * 2 ^2) 相当于计算 (eax * 8) + (ebx * 4) mov eax,dword ptr ds:[x] mov ebx,dword ptr ds:[y] sal eax,3 ; eax * 8 (有符号乘法) shl ebx,2 ; ebx * 4 (无符号乘法) add eax,ebx ; eax + ebx invoke crt_printf,addr szFmt,eax invoke ExitProcess,0 main ENDP END main

乘法优化的知识点基本就这些,除了两个未知变量的相乘无法优化外,其他形式的乘法运算均可以进行优化,如果表达式中存在一个常量值,那编译器则会匹配各种优化策略,最后对不符合优化策略的运算进行调整,如果真的无法优化,则会使用原始乘法指令计算。

本文作者: 王瑞本文链接: https://www.lyshark.com/post/ade8241c.html版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有