web-dev-qa-db-ja.com

ビット単位の乗算と加算Java

掛け算と足し算の両方を行う方法はありますが、頭を悩ませることができません。どちらも外部のWebサイトからのものであり、私自身のものではありません。

public static void bitwiseMultiply(int n1, int n2) {
    int a = n1, b = n2, result=0;
    while (b != 0) // Iterate the loop till b==0
    {
        if ((b & 01) != 0) // Logical ANDing of the value of b with 01
        {
            result = result + a; // Update the result with the new value of a.
        }
        a <<= 1;              // Left shifting the value contained in 'a' by 1.
        b >>= 1;             // Right shifting the value contained in 'b' by 1.
    }
    System.out.println(result);
}

public static void bitwiseAdd(int n1, int n2) {
    int x = n1, y = n2;
    int xor, and, temp;
    and = x & y;
    xor = x ^ y;

    while (and != 0) {
        and <<= 1;
        temp = xor ^ and;
        and &= xor;
        xor = temp;
    }
    System.out.println(xor);
}

ステップバイステップのデバッグを試してみましたが、実際には機能しますが、あまり意味がありませんでした。

私がおそらく探しているのは、これがどのように機能するかを理解しようとすることです(おそらく数学的な基礎ですか?)。

編集:これは宿題ではありません。Javaでビット演算を学習しようとしています。

14
user183037

乗算コードを調べることから始めましょう。アイデアは実際にはかなり賢いです。あなたがnを持っていると仮定します1 およびn2 バイナリで書かれています。次に、n1を2の累乗の合計と考えることができます。n2= c30 230 + c29 229 + ... + c1 21 + c 2、ここで各c は0または1のいずれかです。次に、積nについて考えることができます。1 n2 なので

n1 n2 =

n1 (c30 230 + c29 229 + ... + c1 21 + c 2)=

n1 c30 230 + n1 c29 229 + ... + n1 c1 21 + n1 c 2

これは少し密度が高いですが、2つの数値の積は、最初の数値に2番目の数値を構成する2の累乗を掛け、2番目の数値の2進数の値を掛けたもので与えられるという考え方です。

ここで問題となるのは、実際の乗算を行わずにこの合計の項を計算できるかどうかです。そのためには、nの2進数を読み取れる必要があります。2。幸い、シフトを使用してこれを行うことができます。特に、nから始めると仮定します。2 そして最後のビットを見てください。それはcです。次に値を1つ下にシフトすると、最後のビットはcになります。、など。より一般的には、nの値をシフトした後2 i桁下がると、最下位ビットはcになります。最後のビットを読み取るには、値に数値1をビット単位でAND演算します。これは、最後の桁を除くすべての場所でゼロであるバイナリ表現を持っています。任意のnに対して0AND n = 0であるため、これにより最上位ビットがすべてクリアされます。さらに、0 AND 1 = 0および1AND 1 = 1であるため、この操作は数値の最後のビットを保持します。

わかりました-cの値を読み取ることができることがわかりました;だから何?幸いなことに、級数nの値も計算できます。1 2 同様の方法で。特に、値のシーケンスnを考慮してください1 << 0、n1 << 1など。左ビットシフトを実行するときはいつでも、2の累乗を掛けることに相当します。これは、上記の合計を計算するために必要なすべてのコンポーネントが揃ったことを意味します。これがあなたのオリジナルのソースコードで、何が起こっているのかコメントされています:

public static void bitwiseMultiply(int n1, int n2) {
    /* This value will hold n1 * 2^i for varying values of i.  It will
     * start off holding n1 * 2^0 = n1, and after each iteration will 
     * be updated to hold the next term in the sequence.
     */
    int a = n1;

    /* This value will be used to read the individual bits out of n2.
     * We'll use the shifting trick to read the bits and will maintain
     * the invariant that after i iterations, b is equal to n2 >> i.
     */
    int b = n2;

    /* This value will hold the sum of the terms so far. */
    int result = 0;

    /* Continuously loop over more and more bits of n2 until we've
     * consumed the last of them.  Since after i iterations of the
     * loop b = n2 >> i, this only reaches zero once we've used up
     * all the bits of the original value of n2.
     */
    while (b != 0)
    {
        /* Using the bitwise AND trick, determine whether the ith 
         * bit of b is a zero or one.  If it's a zero, then the
         * current term in our sum is zero and we don't do anything.
         * Otherwise, then we should add n1 * 2^i.
         */
        if ((b & 1) != 0)
        {
            /* Recall that a = n1 * 2^i at this point, so we're adding
             * in the next term in the sum.
             */
            result = result + a;
        }

        /* To maintain that a = n1 * 2^i after i iterations, scale it
         * by a factor of two by left shifting one position.
         */
        a <<= 1;

        /* To maintain that b = n2 >> i after i iterations, shift it
         * one spot over.
         */
        b >>>= 1;
    }

    System.out.println(result);
}

お役に立てれば!

24
templatetypedef

問題はJavaではなく、2進数で計算しているようです。シンプルの始まり:(すべての数字は2進数:)

0 + 0 = 0   # 0 xor 0 = 0
0 + 1 = 1   # 0 xor 1 = 1
1 + 0 = 1   # 1 xor 0 = 1
1 + 1 = 10  # 1 xor 1 = 0 ( read 1 + 1 = 10 as 1 + 1 = 0 and 1 carry)

わかりました... xor演算を使用して2つの1桁の数値を追加できることがわかります。とを使用すると、「キャリー」ビットがあるかどうかを確認できます。これは、ペンと紙で数字を追加するのと非常によく似ています。 (この時点まで、半加算器と呼ばれるものがあります)。次の2ビットを追加するときは、それらの2桁にキャリービットも追加する必要があります。これを考慮に入れると、全加算器を取得できます。ウィキペディアで半加算器と全加算器の概念について読むことができます: http://en.wikipedia.org/wiki/Adder_(electronics )そしてウェブ上の他の多くの場所。それがあなたのスタートになることを願っています。

ちなみに掛け算はとても似ています。小学校でペンと紙を掛けた方法を覚えておいてください。それがここで起こっていることです。 10進数ではなく、2進数で発生しているだけです。

5
yankee

これが乗算の別のアプローチです

/**
 * Multiplication of binary numbers without using '*' operator
 * uses bitwise Shifting/Anding
 *
 * @param n1
 * @param n2
 */
public static void multiply(int n1, int n2) {
    int temp, i = 0, result = 0;

    while (n2 != 0) {
        if ((n2 & 1) == 1) {
            temp = n1;

            // result += (temp>>=(1/i)); // To do it only using Right shift
            result += (temp<<=i); // Left shift (temp * 2^i)
        }
        n2 >>= 1;   // Right shift n2 by 1.
        i++;
    }

    System.out.println(result);
}
0
Hamzeen Hameem