最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

匯編高效乘法運算的具體使用方法

 更新時間:2024年03月26日 09:54:08   作者:微軟技術分享  
在匯編語言中,乘法指令通常是通過mul(無符號乘法)和imul(有符號乘法)這兩個指令實現的,本文就來詳細的介紹一下匯編高效乘法運算,感興趣的可以了解一下

乘法指令是一種在CPU中實現的基本算術操作,用于計算兩個數的乘積。在匯編語言中,乘法指令通常是通過mul(無符號乘法)imul(有符號乘法)這兩個指令實現的。由于乘法指令在執(zhí)行時所消耗的時鐘周期較多,所以編譯器在優(yōu)化代碼時通常會嘗試將乘法操作轉換為更高效的加法、和移位操作。

  • 對于較小的數,編譯器可能會選擇將乘法操作直接轉換為加法操作。例如,將表達式a * b轉換為a + a + ... + a(b次相加)的形式。這種方式可以通過循環(huán)展開、代碼向量化等技術來優(yōu)化。

  • 對于較大的數,編譯器可能會使用位移和移位操作來代替乘法。例如,將表達式a * b轉換為a << n + a << m的形式,其中nm為符合條件的位數。這種方式可以通過位移指令的高效性來加速運算。

當以上方式均無法進行優(yōu)化時,編譯器才會使用mul/imul指令來執(zhí)行乘法操作。這兩條指令可以對無符號數和有符號數進行乘法運算,即便這兩條指令會使用更多的時鐘周期,但乘法指令的計算效率相對于其他指令DIV來說仍然較低,因此在編寫高效代碼時,應盡可能地避免使用乘法操作,并結合使用上面提到的技巧進行優(yōu)化。

使用IMUL指令完成乘法

要計算乘法在不考慮執(zhí)行效率的情況下編譯器通常會直接使用imul指令完成計算,imul指令在一些情況下可以比其他乘法指令(如mul指令)更快地執(zhí)行乘法運算,但性能較低的原因主要是由于imul指令通常用于有符號數的乘法運算,并且在執(zhí)行時需要處理符號位的擴展和溢出問題,這轉換成了額外的指令和時鐘周期的消耗。如果對于無符號整數或需要使用寄存器的低位或者高位結果的情況,使用imul指令可以提供一定的優(yōu)勢。

計算乘法時應遵循:

  • 如果乘數與被乘數都是8位 則把AL做乘數,結果放在AX
  • 如果乘數與被乘數都是16位 將把AX做乘數,結果放在EAX
  • 如果乘數與被乘數都是32位 將把EAX做乘數,結果放在EDX:EAX

乘法指令計算很簡單,只需要累加乘數即可,如下所示則是一個簡單的計算三個數相乘的匯編實現;

.data
    x DWORD ?
    y DWORD ?
    z DWORD ?
    szFmt BYTE '計算結果: %d',0dh,0ah,0
.code
    main PROC
      mov dword ptr ds:[x],10
      mov dword ptr ds:[y],24
      mov dword ptr ds:[z],18
      
      ; 計算 x * y * z
      mov eax,dword ptr ds:[x]
      imul eax,dword ptr ds:[y]
      imul eax,dword ptr ds:[z]
      invoke crt_printf,addr szFmt,eax
    main ENDP
END main

使用LEA指令替換乘法

在實際編程中,我們可以使用LEA指令來替代乘法操作,從而提高代碼的執(zhí)行效率。但讀者需要注意,在使用LEA計算乘法時必須要保證乘數是2的次冪,并且乘數的范圍必須是2/4/8這三個區(qū)間才可使用該指令,我們使用匯編來實現計算eax*8+2其匯編指令如下。

  • 假設 eax=5 計算 eax * 8 + 2 的結果,拆分過程如下:
  • 1.計算 lea ebx,dword ptr ds:[eax * 8 + 2] 這就相當于計算 ebx = (eax * 8) +2直接可得到結果。

第一個案例比較簡單,可直接使用一條lea指令即可完成計算過程,只要保證被乘數是2的次冪即可。

.data
  x DWORD ?
  szFmt BYTE '計算結果: %d',0dh,0ah,0
.code
  main PROC
    ; 針對乘法的lea指令優(yōu)化
    mov dword ptr ds:[x],5
    
    mov eax,dword ptr ds:[x]               ; eax = x
    xor ebx,ebx                            ; ebx = 0
    lea ebx,dword ptr ds:[eax * 8 + 2]     ; ebx = eax * 8 + 2
    invoke crt_printf,addr szFmt,ebx
    
    invoke ExitProcess,0
  main ENDP
END main

使用LEA指令拆分計算

如果我們計算的乘法超出了2/4/8次冪范圍,則需要對乘法進行拆分,拆分時也應遵循2的次冪原則,拆分后在分開來計算。

  • 假設 eax=3 計算 15 * eax 的結果,拆分過程如下:
  • 1.計算 lea edx,[eax * 4 + eax] 這就相當于計算 edx = (4 * eax) + eax = 5eax 其中的每個edx就相當于5個eax
  • 2.計算 lea edx,[edx * 2 + edx] 這就相當于計算 edx = (5 * eax) * 2 + (5 * eax)
  • 3.計算 (5eax * 2) = 10eax 接著計算 (5 * eax) = 5eax 最后得出 10eax + 5eax
  • 4.經過該過程可得出 eax * 15 = 45 最終計算3*15=45得到最終結果.

這個計算過程看似復雜,但如果將其轉化為匯編指令那么只需要兩條即可實現快速乘法運算。

.data
  x DWORD ?
  szFmt BYTE '計算結果: %d',0dh,0ah,0
.code
  main PROC
    ; 針對乘法的lea指令優(yōu)化
    mov dword ptr ds:[x],3
    
    ; 如果使用lea計算乘法,則乘數必須是2/4/8
    mov eax,dword ptr ds:[x]               ; eax = 3
    lea edx,dword ptr ds:[eax * 4 + eax]   ; edx = 4eax + eax 得出 5eax,也就是說每一個edx就代表5個eax
    lea edx,dword ptr ds:[edx * 2 + edx]   ; edx = (5eax * 2) + 5eax 最終得出 15eax
    invoke crt_printf,addr szFmt,edx       ; edx = eax * 15 計算后得出 45
    
    invoke ExitProcess,0
  main ENDP
END main

使用LEA指令遞減計算

如果計算乘法時乘數非2的次冪,這種情況下需要減去特定的值,例如當我們計算eax * 7時,由于7非二的次冪,我們無法通過lea指令進行計算,但我們可以計算eax * 8計算出的結果減去一個eax同樣可以得到正確的值。

  • 假設 eax=3 計算 eax * 7 + 10 的結果,拆分過程如下:
  • 1.計算 lea edx,dword ptr ds:[eax * 8] 這就相當于計算 edx = (8 * eax)
  • 2.計算 sub edx,eax 這就相當于計算 edx = (8 * eax) - eax
  • 3.計算 add edx,10 這就相當于計算 edx = ( (8 * eax) - eax ) + 10
  • 4.經過如上計算,我們就可以計算出eax * 7 + 10的最終結果

這個計算過程看似復雜,但其實在匯編層面并不難構建,如下分別實現計算兩個表達式求值過程。

.data
  x DWORD ?
  szFmt BYTE '計算結果: %d',0dh,0ah,0
.code
  main PROC
    ; 針對乘法的lea指令優(yōu)化
    mov dword ptr ds:[x],3
    
    ; 如果計算乘法時乘數非2的次冪,則此時需要減

    ; 計算 edx = eax * 7 + 10
    mov eax,dword ptr ds:[x]               ; eax = 3 => 計算 eax * 7 + 10
    lea edx,dword ptr ds:[eax * 8]         ; edx = eax * 8
    sub edx,eax                            ; edx = edx - eax
    add edx,10                             ; edx = edx + 10
    invoke crt_printf,addr szFmt,edx       ; edx = eax * 7 + 10
    
    ; 計算 edx = eax * 3 - 7
    mov eax,dword ptr ds:[x]               ; eax = 3 => 計算 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

使用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

使用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

乘法優(yōu)化的知識點基本就這些,除了兩個未知變量的相乘無法優(yōu)化外,其他形式的乘法運算均可以進行優(yōu)化,如果表達式中存在一個常量值,那編譯器則會匹配各種優(yōu)化策略,最后對不符合優(yōu)化策略的運算進行調整,如果真的無法優(yōu)化,則會使用原始乘法指令計算。

到此這篇關于匯編高效乘法運算的具體使用方法的文章就介紹到這了,更多相關匯編 乘法運算內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 匯編實現冒泡排序的方法示例

    匯編實現冒泡排序的方法示例

    這篇文章主要介紹了匯編實現冒泡排序的方法示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-02-02
  • 匯編語言乘指令 MUL、IMUL的具體使用

    匯編語言乘指令 MUL、IMUL的具體使用

    這篇文章主要介紹了匯編語言乘指令 MUL、IMUL的具體使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-02-02
  • DEBUG 命令詳解

    DEBUG 命令詳解

    這篇文章主要介紹了DEBUG 命令詳解,需要的朋友可以參考下
    2006-12-12
  • 匯編指令:JO、JNO、JB..的使用方法

    匯編指令:JO、JNO、JB..的使用方法

    這篇文章主要介紹了匯編指令:JO、JNO、JB..的使用方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-01-01
  • 匯編語言之寄存器詳解

    匯編語言之寄存器詳解

    這篇文章主要介紹了匯編語言之寄存器詳解,需要的朋友可以參考下
    2020-01-01
  • 匯編語言指令mov、add、sub、jmp詳解

    匯編語言指令mov、add、sub、jmp詳解

    這篇文章主要介紹了匯編語言指令mov、add、sub、jmp詳解,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-02-02
  • 在vs2017中編寫匯編的實現(圖文)

    在vs2017中編寫匯編的實現(圖文)

    這篇文章主要介紹了在vs2017中編寫匯編的實現(圖文),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-03-03
  • 匯編語言實現在指定字符串中搜索字符''A''的方法

    匯編語言實現在指定字符串中搜索字符''A''的方法

    這篇文章主要介紹了匯編語言實現在指定字符串中搜索字符'A'的方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-02-02
  • 匯編語言系列之匯編實現簡單數學運算

    匯編語言系列之匯編實現簡單數學運算

    這篇文章主要介紹了匯編語言系列之匯編實現簡單數學運算的思路詳解,本文給大家列出了兩種算術運算的代碼,設計思路給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-11-11
  • C 表達式中的匯編指令

    C 表達式中的匯編指令

    這篇文章主要介紹了C 表達式中的匯編指令,需要的朋友可以參考下
    2020-01-01

最新評論

衢州市| 师宗县| 长兴县| 天津市| 霞浦县| 格尔木市| 沿河| 南召县| 耿马| 西乡县| 抚松县| 合水县| 衡山县| 达孜县| 曲松县| 香港 | 朔州市| 商南县| 永泰县| 浮梁县| 莱州市| 青浦区| 贡山| 城步| 天台县| 澎湖县| 德阳市| 宁海县| 高碑店市| 德化县| 锡林浩特市| 喀什市| 隆化县| 洛南县| 修文县| 介休市| 烟台市| 汽车| 永修县| 凤冈县| 基隆市|