我们必须将两个数字x和y相乘,但我们不能使用*运算符。
一种简单的方法是添加x,y次或添加y,x次,这很简单并且是线性的。
第二种方法是选择任意数字(比如x)并查看在该数字中设置的所有位,如果设置了第i位,则执行以下操作:
product +=y<<i//product is 0 initially and do this for all i.
显然对于32位数字,循环运行32次并且其时间复杂度是恒定的。
我的问题是,还有其他办法吗?记住我们不能使用*。
答案 0 :(得分:2)
假设两个数字都是无符号的,可以做(这或多或少等同于你的第二种方式)
p = 0
while x > 0
while x is even
x = x / 2 // a shift right operation
y = y + y // a shift left operation
x = x - 1
p = p + y
该产品现在位于p
。
要了解为什么这是正确的,请考虑不变
product = p + x*y
它由算法中的所有循环维护。我们从p = 0开始,所以它在开始时结束,当x = 0时结束,所以我们必须得到product = p。
答案 1 :(得分:1)
在某些体系结构中,可以使用单个指令在单词中设置第一个/最后一个位。
E.g。 GCC具有__builtin_clz (unsigned int x)
,它返回X中前导0位的数量。
或者strings.h中有int ffs(int i)
,它返回单词i
中第一个(最低有效)位集的位置。
使用其中一个,您只能枚举一个单词中的设置位。这可以减少所需的迭代次数。
#include <stdlib.h>
#include <stdio.h>
#include <strings.h>
int main(int argc, char** argv)
{
if(argc >= 2) {
int a = atoi(argv[1]);
int b = atoi(argv[2]);
printf("%i * %i = %i", a, b, a*b);
int r = 0;
while (a) {
int i = ffs(a) - 1;
a ^= 1<<i;
r += b<<i;
}
printf(" = %i\n", r);
}
}
使用此代码,乘法1048576 * 123 = 128974848
将在单次迭代中完成,因为1048576 = 0x100000
只有一位设置。
答案 2 :(得分:0)
在没有*
的情况下相乘解决方案1有整数:
我假设您可以使用+
做一个循环:x + x + .. + x(y次)。或y + ... + y(x次)。
解决方案2:
分解所有内容,为每个数字0-9保留一张x * y表,并重现手动操作,就像在小学一样。
解决方案3:结合其他两个方面,最简单,最强大:
对于整数:以二进制方式执行
13 * 7:
1101 * 111 = 1101 + 11010 + 110100 = 1011011 = 91
处理器的工作方式就是这样。没有+,只有二进制操作(和,或,xor)
对于非整数:用管理0的整数
进行对于负数:同样的事情,管理+/-
时间复杂度在32位时保持不变:这是无关紧要的,因为一切都是不变的。
一般的时间复杂度:二元运算非常有效:
位数= O(log n)
=&GT; x * y =&gt; O(log x)* O(log y)