如何在没有'*'运算符的情况下执行乘法运算?

时间:2010-01-15 04:20:08

标签: java c++ c bit-manipulation

当我正在学习C时,我只是经历了一些基本的东西。我遇到了一个问题,即在不使用*运算符的情况下将数字乘以7。基本上就像这样

      (x << 3) - x;

现在我知道了基本的位操作操作,但我不知道如何在不使用*运算符的情况下将数字乘以任何其他奇数?是否有一般的算法?

33 个答案:

答案 0 :(得分:59)

考虑如何使用铅笔和纸张以十进制相乘:

  12
x 26
----
  72
 24
----
 312

乘法在二进制中看起来像什么?

   0111
x  0101
-------
   0111
  0000
 0111
-------
 100011

注意什么?与十进制中的乘法不同,您需要记住“时间表”,当乘以二进制时,您总是将其中一个项乘以0或1,然后再将其写入列表加数。没有时间表需要。如果第二项的数字为1,则在第一项中添加。如果是0,则不然。另请注意加数如何逐步向左移动。

如果您不确定这一点,请在纸上进行一些二进制乘法。完成后,将结果转换回十进制,看看它是否正确。在你完成了一些之后,我想你会明白如何使用移位和添加来实现二进制乘法。

答案 1 :(得分:25)

每个人都忽视了显而易见的事实。不涉及乘法:

10^(log10(A) + log10(B))

答案 2 :(得分:19)

左移整数乘以2,前提是它不会溢出。只需在收到后即可添加或减少。

答案 3 :(得分:19)

问题是:

  

将数字乘以7而不使用*运算符

这不使用*

 number / (1 / 7) 

修改
这在C中编译并正常工作:

 int number,result;
 number = 8;
 result = number / (1. / 7);
 printf("result is %d\n",result);

答案 4 :(得分:17)

int multiply(int multiplicand, int factor)
{
    if (factor == 0) return 0;

    int product = multiplicand;
    for (int ii = 1; ii < abs(factor); ++ii) {
        product += multiplicand;
    }

    return factor >= 0 ? product : -product;
}

你想要没有*的乘法,你得到它,伙计!

答案 5 :(得分:12)

很容易避免'*'运算符:

mov eax, 1234h
mov edx, 5678h
imul edx

看不见'*'。当然,如果你想深入了解它的精神,你也可以使用可靠的旧班次并添加算法:

mult proc
; Multiplies eax by ebx and places result in edx:ecx
    xor ecx, ecx
    xor edx, edx
mul1:
    test ebx, 1
    jz  mul2
    add ecx, eax
    adc edx, 0
mul2:
    shr ebx, 1
    shl eax, 1
    test ebx, ebx
    jnz  mul1
done:
    ret
mult endp

当然,对于现代处理器,所有(?)都有乘法指令,但是当PDP-11闪亮且新的时候,这样的代码看起来很实用。

答案 6 :(得分:10)

从数学角度讲,乘法分配而不是添加。从本质上讲,这意味着:

  

x *(a + b + c ...)=(x * a)+(x * b)+(x * c)...

任何实数(在您的情况下为7),都可以表示为一系列添加(例如8 + (-1),因为减法实际上只是添加错误的方式)。这允许您将任何单个乘法语句表示为等效的乘法语句系列,这将产生相同的结果:

x * 7
= x * (8 + (-1))
= (x * 8) + (x * (-1))
= (x * 8) - (x * 1)
= (x * 8) - x

按位移位运算符基本上只是将数字乘以或除以2的幂。只要您的等式只处理这些值,就可以使用位移来替换所有出现的乘法运算符。

  

(x * 8) - x =(x * 2 3 ) - x =(x <&lt; 3) - x

类似的策略可以用于任何其他整数,无论​​是奇数还是偶数都没有区别。

答案 7 :(得分:8)

x*8-x = x*(8-1) = x*7

相同

答案 8 :(得分:7)

任何数字,奇数或偶数,可以表示为2的幂之和。例如,

     1   2   4   8
------------------
 1 = 1
 2 = 0 + 2
 3 = 1 + 2
 4 = 0 + 0 + 4
 5 = 1 + 0 + 4
 6 = 0 + 2 + 4
 7 = 1 + 2 + 4
 8 = 0 + 0 + 0 + 8
11 = 1 + 2 + 0 + 8

因此,您可以通过执行正确的移位和添加来将x乘以任意数字。

 1x = x
 2x = 0 + x<<1
 3x = x + x<<1
 4x = 0 +  0   + x<<2
 5x = x +  0   + x<<2
11x = x + x<<1 +   0  + x<<3

答案 9 :(得分:5)

当它归结为它时,乘以正整数可以这样做:

int multiply(int a, int b) {
  int ret = 0;
  for (int i=0; i<b; i++) {
    ret += b;
  }
  return ret;
}

高效?几乎不。但这是正确的(考虑到整数的限制等等)。

因此,使用左移只是乘以2的快捷方式。但是,一旦达到b下的最高2次幂,您只需添加a所需的次数,这样:

int multiply(int a, int b) {
  int ret = a;
  int mult = 1;
  while (mult <= b) {
    ret <<= 1;
    mult <<= 1;
  }
  while (mult < b) {
    ret += a;
  }
  return ret;
}

或接近那个。

换句话说,乘以7。

  • 左移2(第4次)。左移3是8,其> 7;
  • 添加b 3次。

答案 10 :(得分:4)

O(log(b))方法

public int multiply_optimal(int a, int b) {

    if (a == 0 || b == 0)
        return 0;
    if (b == 1)
        return a;
    if ((b & 1) == 0)
        return multiply_optimal(a + a, b >> 1);
    else
        return a + multiply_optimal(a + a, b >> 1);

}

复原代码的工作原理如下:
基本情况:
如果数字中的任何一个为0,则产品为0 如果b = 1,则产品= a。

如果b是偶数:
ab可以写成2a(b / 2)
2a(b / 2)=(a + a)(b / 2)=(a + a)(b>&gt; 1)其中'&gt;&gt;' java中的arithematic右移运算符。

如果b为奇数:
ab可以写成+ a(b-1)
一个+ A(B-1)= A + 2A(B-1)/ 2 = A +(A + A)(B-1)/ 2 = A +(A + A)((B-1)GT;&GT; 1)
由于b是奇数(b-1)/ 2 = b / 2 = b>&gt; 1
所以ab = a +(2a *(b>&gt; 1))
注意:每个递归调用b减半=&gt;为O(log(b))的

答案 11 :(得分:4)

一天晚上,我发现我非常无聊,并把它煮熟了:

#include <iostream>

typedef unsigned int uint32;

uint32 add(uint32 a, uint32 b) {
    do {
        uint32 s = a ^ b;
        uint32 c = a & b;
        a = s;
        b = c << 1;
    } while (a & b)
    return (a | b)
}

uint32 mul(uint32 a, uint32 b) {
    uint32 total = 0;
    do {
        uint32 s1 = a & (-(b & 1))
        b >>= 1; a <<= 1;
        total = add(s1, total)
    } while (b)
    return total;
}

int main(void) {
    using namespace std;
    uint32 a, b;

    cout << "Enter two numbers to be multiplied: ";
    cin >> a >> b;

    cout << "Total: " << mul(a,b) << endl;
    return 0;
}

上面的代码应该是不言自明的,因为我试图尽可能简单。它应该或多或少地工作在CPU执行这些操作的方式上。我所知道的唯一错误是a不允许大于32,767且b不允许大到足以溢出a(也就是说,乘法溢出是未处理,因此无法进行64位结果)。如果输入正确reinterpret_cast<>,它甚至应该使用负数。

答案 12 :(得分:3)

unsigned int Multiply(unsigned int m1, unsigned int m2)
{
    unsigned int numBits = sizeof(unsigned int) * 8; // Not part of the core algorithm
    unsigned int product = 0;
    unsigned int mask = 1;
    for(int i =0; i < numBits; ++i, mask = mask << 1)
    {
        if(m1 & mask)
        {
            product += (m2 << i);
        }
    }
    return product;
}

答案 13 :(得分:2)

import java.math.BigInteger;

public class MultiplyTest {
    public static void main(String[] args) {
        BigInteger bigInt1 = new BigInteger("5");
        BigInteger bigInt2 = new BigInteger("8");
        System.out.println(bigInt1.multiply(bigInt2));
    }
}

答案 14 :(得分:2)

当被乘数为负时,Shift和add不起作用(即使使用符号扩展名)。有符号乘法必须使用Booth encoding

完成

LSB开始,从0到1的变化为-1;从1到0的变化是1,否则为0.在LSB下面还有一个隐含的额外位0。

例如,数字5(0101)将编码为:(1)( - 1)(1)( - 1)。您可以验证这是否正确:

5 = 2 ^ 3 - 2 ^ 2 + 2 -1

此算法也适用于2的补码形式的负数:

4位2的补码中的

-1是1111.使用Booth算法:(1)(0)(0)(0)( - 1),其中最左边的位1没有空格所以我们得到:(0)(0)(0)( - 1),它是-1。

/* Multiply two signed integers using the Booth algorithm */
int booth(int x, int y)
{
    int prev_bit = 0;
    int result = 0;

    while (x != 0) {
        int current_bit = x & 0x1;
        if (prev_bit & ~current_bit) {
            result += y;
        } else if (~prev_bit & current_bit) {
            result -= y;
        }

        prev_bit = current_bit;

        x = static_cast<unsigned>(x) >> 1;
        y <<= 1;
    }

    if (prev_bit)
        result += y;

    return result;
}

以上代码不检查溢出。下面是一个略微修改的版本,它将两个16位数相乘并返回一个32位数,因此它永远不会溢出:

/* Multiply two 16-bit signed integers using the Booth algorithm */
/* Returns a 32-bit signed integer */
int32_t booth(int16_t x, int16_t y)
{
    int16_t prev_bit = 0;
    int16_t sign_bit = (x >> 16) & 0x1;
    int32_t result = 0;
    int32_t y1 = static_cast<int32_t>(y);

    while (x != 0) {
        int16_t current_bit = x & 0x1;
        if (prev_bit & ~current_bit) {
            result += y1;
        } else if (~prev_bit & current_bit) {
            result -= y1;
        }

        prev_bit = current_bit;

        x = static_cast<uint16_t>(x) >> 1;
        y1 <<= 1;
    }

    if (prev_bit & ~sign_bit)
        result += y1;

    return result;
}

答案 15 :(得分:2)

unsigned int Multiply( unsigned int a, unsigned int b )
{
    int ret = 0;
    // For each bit in b
    for (int i=0; i<32; i++) {

        // If that bit is not equal to zero
        if (( b & (1 << i)) != 0) {

            // Add it to our return value
            ret += a << i;
        }
    }
    return ret;
}

我避开了符号位,因为它不是帖子的主题。这是Wayne Conrad基本上所说的实现。 Here is another problem is you want to try more low level math operations. Project Euler很酷!

答案 16 :(得分:2)

@Wang,这是一个很好的概括。但这是一个稍微快一点的版本。但它假定没有溢出而a是非负的。

int mult(int a, int b){
    int p=1;
    int rv=0;
    for(int i=0; a >= p && i < 31; i++){
        if(a & p){
            rv += b;
        }
        p = p << 1;
        b = b << 1;
    }

    return rv;
}

最多循环1 + log_2(a)次。如果在&gt;时交换a和b,可能会更快湾

答案 17 :(得分:1)

JAVA:
考虑到这一事实,每个数字都可以分为两个权力:

1 = 2 ^ 0
2 = 2 ^ 1
3 = 2 ^ 1 + 2 ^ 0
...

我们希望得到x其中:
x = n * m

因此,我们可以通过以下步骤实现这一目标:

1.   while m is greater or equal to 2^pow:
     1.1  get the biggest number pow, such as 2^pow is lower or equal to m
     1.2  multiply n*2^pow and decrease m to m-2^pow
2.   sum the results

使用递归的示例实现:

long multiply(int n, int m) {
    int pow = 0;
    while (m >= (1 << ++pow)) ;
    pow--;
    if (m == 1 << pow) return (n << pow);
    return (n << pow) + multiply(n, m - (1 << pow));
}

我在上次面试中得到了这个问题,这个答案被接受了。

编辑:正数的解决方案

答案 18 :(得分:1)

对于正数,这是最简单的C99 / C11解决方案:

unsigned multiply(unsigned x, unsigned y) { return sizeof(char[x][y]); }

答案 19 :(得分:1)

在C#中:

private static string Multi(int a, int b)
{
    if (a == 0 || b == 0)
        return "0";

    bool isnegative = false;

    if (a < 0 || b < 0)
    {
        isnegative = true;

        a = Math.Abs(a);

        b = Math.Abs(b);
    }

    int sum = 0;

    if (a > b)
    {
        for (int i = 1; i <= b; i++)
        {
            sum += a;
        }
    }
    else
    {
        for (int i = 1; i <= a; i++)
        {
            sum += b;
        }
    }

    if (isnegative == true)
        return "-" + sum.ToString();
    else
        return sum.ToString();
}

答案 20 :(得分:1)

如果可以使用日志功能:

public static final long multiplyUsingShift(int a, int b) {
    int absA = Math.abs(a);
    int absB = Math.abs(b);

    //Find the 2^b which is larger than "a" which turns out to be the 
    //ceiling of (Log base 2 of b) == numbers of digits to shift
    double logBase2 = Math.log(absB) / Math.log(2);
    long bits = (long)Math.ceil(logBase2);

    //Get the value of 2^bits
    long biggerInteger = (int)Math.pow(2, bits);

    //Find the difference of the bigger integer and "b"
    long difference = biggerInteger - absB;

    //Shift "bits" places to the left
    long result = absA<<bits;

    //Subtract the "difference" "a" times
    int diffLoop = Math.abs(a);
    while (diffLoop>0) {
        result -= difference;
        diffLoop--;
    }

    return (a>0&&b>0 || a<0&&b<0)?result:-result;
}

如果您无法使用日志功能:

public static final long multiplyUsingShift(int a, int b) {
    int absA = Math.abs(a);
    int absB = Math.abs(b);

    //Get the number of bits for a 2^(b+1) larger number
    int bits = 0;
    int bitInteger = absB;
    while (bitInteger>0) {
        bitInteger /= 2;
        bits++;
    }

    //Get the value of 2^bit
    long biggerInteger = (int)Math.pow(2, bits);

    //Find the difference of the bigger integer and "b"
    long difference = biggerInteger - absB;

    //Shift "bits" places to the left
    long result = absA<<bits;

    //Subtract the "difference" "a" times
    int diffLoop = absA;
    while (diffLoop>0) {
        result -= difference;
        diffLoop--;
    }

    return (a>0&&b>0 || a<0&&b<0)?result:-result;
}

我发现这更有效:

public static final long multiplyUsingShift(int a, int b) {
    int absA = Math.abs(a);
    int absB = Math.abs(b);

    long result = 0L;
    while (absA>0) {
        if ((absA&1)>0) result += absB; //Is odd
        absA >>= 1;
        absB <<= 1;
    }

    return (a>0&&b>0 || a<0&&b<0)?result:-result;
}

还有另一种方式。

public static final long multiplyUsingLogs(int a, int b) {
    int absA = Math.abs(a);
    int absB = Math.abs(b);
    long result = Math.round(Math.pow(10, (Math.log10(absA)+Math.log10(absB))));
    return (a>0&&b>0 || a<0&&b<0)?result:-result;
}

答案 21 :(得分:0)

package com.amit.string;

// Here I am passing two values, 7 and 3 and method getResult() will
// return 21 without use of any operator except the increment operator, ++.
//
public class MultiplyTwoNumber {

    public static void main(String[] args) {
        int a = 7;
        int b = 3;
        System.out.println(new MultiplyTwoNumber().getResult(a, b));
    }

    public int getResult(int i, int j) {
        int result = 0;

        // Check for loop logic it is key thing it will go 21 times
        for (int k = 0; k < i; k++) {
            for (int p = 0; p < j; p++) {
                result++;
            }
        }
        return result;
    }
}

答案 22 :(得分:0)

public static int multiply(int a, int b) 
{
    int temp = 0;
    if (b == 0) return 0;
    for (int ii = 0; ii < abs(b); ++ii) {
        temp = temp + a;
    }

    return b >= 0 ? temp : -temp;
}

public static int abs(int val) {

    return val>=0 ? val : -val;
}

答案 23 :(得分:0)

public static void main(String[] args) {
    System.out.print("Enter value of A -> ");
    Scanner s=new Scanner(System.in);
    double j=s.nextInt();
    System.out.print("Enter value of B -> ");
    Scanner p=new Scanner(System.in);
    double k=p.nextInt();
    double m=(1/k);
    double l=(j/m);
    System.out.print("Multiplication of A & B=> "+l);
}

答案 24 :(得分:0)

循环它。运行一个循环七次,然后按你乘以七的数字进行迭代。

伪代码:

total = 0
multiply = 34

loop while i < 7

    total = total + multiply

endloop

答案 25 :(得分:0)

另一种思维开箱即用的答案:

BigDecimal a = new BigDecimal(123);
BigDecimal b = new BigDecimal(2);
BigDecimal result = a.multiply(b);
System.out.println(result.intValue());

答案 26 :(得分:0)

设N是我们想要乘以7的数字。

N x 7 = N + N + N + N + N + N + N
N x 7 = N + N + N + N + N + N + N + (N - N)
N x 7 = (N + N + N + N + N + N + N + N) - N
N x 7 = 8xN - N

我们知道,将任意数字左移一位乘以2.因此,将任意数乘以8相当于将其右移3位

N x 7 = (N << 3) - N 

我在这里找到了这个描述 http://www.techcrashcourse.com/2016/02/c-program-to-multiply-number-by-7-bitwise-operator.html

希望它有所帮助。

答案 27 :(得分:0)

通过使用递归,我们可以将两个整数与给定的约束相乘。

要乘以x和y,递归加x次。

     #include<stdio.h>
     /* function to multiply two numbers x and y*/
     int multiply(int x, int y)
     {
        /* multiplied with anything gives */
        if(y == 0)
        return 0;

        /* Add x one by one */
        if(y > 0 )
        return (x + multiply(x, y-1));

        /* the case where y is negative */
        if(y < 0 )
        return -multiply(x, -y);
     }

     int main()
     {
       printf("\n %d", multiply(5, -11));
       getchar();
       return 0;
     }

答案 28 :(得分:0)

一种用于正数的JavaScript方法

function recursiveMultiply(num1, num2){
    const bigger = num1 > num2 ? num1 : num2; 
    const smaller = num1 <= num2 ? num1 : num2; 
    const indexIncrement = 1;
    const resultIncrement = bigger;

    return recursiveMultiplyHelper(bigger, smaller, 0, indexIncrement, resultIncrement)
}

function recursiveMultiplyHelper(num1, num2, index, indexIncrement, resultIncrement){
    let result = 0;
    if (index === num2){
        return result;
    } 

    if ((index+indexIncrement+indexIncrement) >= num2){
        indexIncrement = 1;
        resultIncrement = num1;
    } else{
        indexIncrement += indexIncrement;
        resultIncrement += resultIncrement;
    }

    result = recursiveMultiplyHelper(num1, num2, (index+indexIncrement), indexIncrement, resultIncrement);
    result += resultIncrement;
    console.log(num1, num2, index, result);

    return result;
}

答案 29 :(得分:0)

考虑我们使用的普通乘法方法

         1101 x        =>13
         0101          =>5
---------------------
         1101
        0000
       1101
      0000
===================        
      1000001 .        => 65

在代码中写上相同的内容

#include<stdio.h>

int multiply(int a, int b){
    int res = 0,count =0;
    while(b>0) {
        if(b & 0x1)
            res = res + (a << count);
        b = b>>1;
        count++;
    }
    return res;
}
int main() {
    printf("Sum of x+y = %d", multiply(5,10));
    return 0;
}

答案 30 :(得分:-1)

非常简单,朋友......每当你离开一个数字时,这意味着你将数字乘以2,这意味着答案是(x <&lt; 3)-x。

答案 31 :(得分:-1)

在没有*运算符的情况下乘以两个数字:

int mul(int a,int b) {
    int result = 0;
    if(b > 0) {
        for(int i=1;i<=b;i++){
            result += a;
        }
    }
    return result;
}

答案 32 :(得分:-3)

丑陋,缓慢且未经测试,但......

int mult(a,b){
    int i, rv=0;
    for(i=0; i < 31; ++i){
        if(a & 1<<i){
            rv += b << i;
        }
    }
    if(a & 1<<31){ // two's complement
        rv -= b<<31;
    }
    return rv;
}