当我正在学习C时,我只是经历了一些基本的东西。我遇到了一个问题,即在不使用*运算符的情况下将数字乘以7。基本上就像这样
(x << 3) - x;
现在我知道了基本的位操作操作,但我不知道如何在不使用*运算符的情况下将数字乘以任何其他奇数?是否有一般的算法?
答案 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。
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)
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;
}