2017-05-09 20 views
-5

私は自由な時間にintelアセンブリ言語(att構文)を学んでいますが、mulコマンドを使用せずに2つの数値を乗算する方法が5と2を一緒にすることができますか?x86アセンブリに2つの32ビットの数値を掛ける

+0

あなたが2の倍数を有するので、あなたは左シフトを使用することができます/ 2倍または2の倍数で複数倍/右にシフトすることができます。 – dawg

+3

こんにちはジャック、あなたはASMで答えが必要な場合は、[アセンブリタグ](http://stackoverflow.com/questions/tagged/assembly)ではなく、[cタグ](http://stackoverflow.com/questions/tagged/c)... – Myst

+0

あなたは 'imul'を使うこともできます。または「ああ」。 – fuz

答えて

1

あなたのCPUが何らかの形で欠陥がある場合を除き、あなたは

:-)だけ使用mulコマンドが希望しかし、一般的な意味で、あなただけの乗算が繰り返し加えていることを認識する必要があり、そう4 x 7は7です一緒に追加された4つの多く:4 + 4 + 4 + 4 + 4 + 4 + 4

ので、そのような獣のための簡単な擬似コードは次のようになります。それは符号なしの使用だと

Line# a b res 
----- --- --- --- 
    1 5 2 ? 
    2    0 
    3     (b>0, keep going) 
    4    5 
    5   1 
    3     (b>0, keep going) 
    4    10 
    5   0 
    3     (b==0, exit loop) 
    6     (returns 10) 

注:

def mul(unsigned a, unsigned b): # line 1 
    res = 0      # line 2 
    while b > 0:     # line 3 
     res = res + a    # line 4 
     b = b - 1     # line 5 
    return res     # line 6 

サンプルドライランでテストデータを使用しては、これがどのように機能するかを示し値を変更するだけで、符号付きの値を扱うことができます。

def mul(int a, int b): 
    sign = 1 
    if a < 0: 
     a = -a 
     sign = -sign 
    if b < 0: 
     b = -b 
     sign = -sign 

    res = 0 
    while a > 0: 
     res = res + b 
     a = a - 1 

    if sign == -1: 
     res = -res 
    return res 

また、ビット(必要に応じて追加を最小限に抑える)値のシフトではなく、単純な繰り返し添加を含む乗算を行うための、実際に、より効率的な方法があることを心に留めておきます。そのことによって

私は9999 x 9999のような計算が約10,000追加は簡単な方法を使用して行う必要がありますを意味します。シフトを使用すると、必要な追加を、数字の1つに9桁、他の数字の1桁に1つだけ制限することができます。つまり、上記の計算で約40個の追加を取り除くことができます。

 9999 x 9 -> nine additions 
+ 99990 x 9 -> nine additions 
+ 999900 x 9 -> nine additions 
+ 9999000 x 9 -> nine additions 
       \____________/ 
         | 
         V 
       three additions 

あなたは、より詳細に作品をシフトする方法を確認したい場合は、ウィキペディアはarticle on the topicを持っている:あなたは9999 x 9999まで簡素化することができますことを認識したときに

この

は、うまくいけば意味をなさないだろう。


実行する必要がある操作を事前に知っているため、定数を乗算するとかなり良いパフォーマンスが得られます。例えば、10でレジスタを掛けることは何か(私の組立日数が過去に長く、念頭に置いて)等を行うことができます。

mul_ax_by_10: push bx  ; save registers 
       shl ax  ; ax <- orig_ax * 2 
       push ax  ; save for later add 
       shl ax 
       shl ax  ; ax <- orig_ax * 8 
       pop bx  ; bx <- orig_ax * 2 
       add ax, bx ; ax <- (orig_ax * 8) + (orig_ax * 2) 
          ; <- orig_ax * (8 + 2) 
          ; <- orig_ax * 10 
       pop bx  ; restore saved register 
       ret   ; result in ax 
+0

確かに、私はCコードでそれを書く方法を知っていますが、アセンブリでそれを行う方法はわかりません。 – jack

+0

シフトコマンドを使って2つの数字を乗算する方法の例を教えてもらえますか? 5と10をバイナリ表現にすると、シフトするとaに5を、bに10を格納したとしましょう。 – jack

+0

@jack:https://en.wikipedia.org/wiki/Multiplication_algorithm#Shift_and_addを参照してください –

0

あなたはで質問をタグ付けされているので、私はあなたが苦労していると仮定しますGCCのインラインアセンブラ。あなたは掛け算をした古き良き小数点日で

- 例えば - 11 * 14は以下のように:

  1. をあなたは乗数(11)= 1の右端の桁を取って、被乗数とそれを掛け(14)は

  2. 14あなたは次の桁を左に取っ=乗数= 1で、被乗数= 14でそれを乗算します。また、結果の代わりに被乗数をシフトすることができます= 140一桁左に結果の小数シフト:1 * 140 = 140。このアルゴリズムは、binarismの勇敢な新しい世界でも有​​効です= 154 14 + 140

  1. は、右端を取る

  2. あなたが最終的な結果に結果を追加しましたビットを乗算器(1011b)の右に移動することによって乗算器(1011b)を乗算する。これを被乗数(1110b)で「乗算」する。これは実際に乗算ではありません。 0 * 1110b = 0と1 * 1110b = 1110bという2つのオプションしかありません。結果はビット0または被乗数に従います。それを最終結果に加えます。

  3. 乗数がヌルより大きい場合、次のビットは乗数の右端のビットとして待機します。 1ビットだけ左に被乗数(上記ステップ2の第二のオプション)とGotoステップをシフト1.

GCCプログラム:

#include <stdio.h> 

unsigned mul (unsigned multiplier, unsigned multiplicand) 
{ 
    unsigned r = 0; 
    while (multiplier) 
    { 
     if (multiplier & 1) r += multiplicand; 
     multiplier >>= 1; 
     multiplicand <<= 1; 
    } 
    return r; 
} 

unsigned mul_asm (unsigned multiplier, unsigned multiplicand) 
{ 
    unsigned result = 0; 

    asm 
    (
     "movl %[multiplier], %%edx;"  // EDX = multiplier 
     "movl %[multiplicand], %%ecx;"  // ECX = multiplicand 
     "xorl %%eax, %%eax;"    // Result = 0 

     "L1:;"        // While-loop 
     "shrl $1, %%edx;"     // Get rightmost bit of the multiplier 
     "jnc 1f;"       // Skip the next line if this bit == 0 
     "leal (%%ecx,%%eax), %%eax;"  // Add multiplicand to result (without changing flags) 
     "1:;"        // Local jump label 
     "leal (,%%ecx,2), %%ecx;"   // Shift multiplicand left by one bit (without changing flags) 
     "jnz L1;"       // While EDX != 0 (zero flag from the shrl-line) 

     "movl %%eax, %[result];"   // Return value 

     : [result] "=m" (result)   // Output 
     : [multiplier] "m" (multiplier), // Input 
      [multiplicand] "m" (multiplicand) 
     : "%eax", "%ecx", "%edx", "cc"  // Clobbered registers & flags 
    ); 

    return result; 
} 

int main (void) 
{ 
    unsigned result, multiplier, multiplicand; 

    multiplier = 17; 
    multiplicand = 23; 

    result = multiplier * multiplicand; 
    printf ("direct: %u * %u = %u\n", multiplier, multiplicand, result); 

    result = mul (multiplier,multiplicand); 
    printf ("mul:  %u * %u = %u\n", multiplier, multiplicand, result); 

    result = mul_asm (multiplier,multiplicand); 
    printf ("mul_asm: %u * %u = %u\n", multiplier, multiplicand, result); 

    return 0; 
} 
関連する問題