除以 9 而不使用除法或乘法运算符
Posted
技术标签:
【中文标题】除以 9 而不使用除法或乘法运算符【英文标题】:Divide by 9 without using division or multiplication operator 【发布时间】:2015-05-31 18:52:40 【问题描述】:这个问题我已经尝试解决了,但没有任何办法。任何指针将不胜感激。
正则减法做除法不是这里的意图,巧妙地使用移位运算符来完成它的意图。
【问题讨论】:
最简单的除法方法是重复减法。 Martin James:不,不是作业,而是geeksforgeeks.org/makemytrip-interview-questions-set-6这个问题。 我想知道为什么人们急于投反对票,以便为自己争取更多的赞成票。 @newbie_old 不是我,但投反对票会让投反对票的人付出代价。它不会给他们加分。 @newbie_old 我已经发布了一个迟来的答案。 【参考方案1】:虽然答案已被接受,但我还是发布我的答案。
更新。这是通过乘以一个循环二进制分数来实现的。十进制 1/9 = 0.1111111 重复出现。在二进制中,即 1/1001 = 0.000111000111000111 重复出现。
请注意,二进制乘法器以 6 位为一组,十进制 7 重复出现。所以我在这里要做的是将被除数乘以 7,将其右移 6 位,然后将其添加到运行商中。但是为了保持重要性,我在加法之后进行移位,并在循环结束后将商q
移位以正确对齐。
对于 32 位 int
(6 位 * 6 次移位 = 36 位),计算循环最多有 6 次迭代。
#include<stdio.h>
int main(void)
unsigned x, y, q, d;
int i, err = 0;
for (x=1; x<100; x++) // candidates
q = 0; // quotient
y = (x << 3) - x; // y = x * 7
while(y) // until nothing significant
q += y; // add (effectively) binary 0.000111
y >>= 6; // realign
q >>= 6; // align
d = x / 9; // the true answer
if (d != q)
printf ("%d / 9 = %d (%d)\n", x, q, d); // print any errors
err++;
printf ("Errors: %d\n", err);
return 0;
不幸的是,由于与乘以十进制 27 * 0.111111 = 2.999999 而不是 3 相同的原因,这对于每个 9 的倍数的候选者来说都失败了,因为舍入错误。所以我现在通过保留 4 ls 来使答案复杂化。用于舍入的商的位。结果是它适用于所有int
值,由两个顶部半字节限制,一个用于* 7
,一个用于* 16
意义。
#include<stdio.h>
int main(void)
unsigned x, y, q, d;
int i, err = 0;
for (x=1; x<0x00FFFFFF; x++)
q = 8; // quotient with (effectively) 0.5 for rounding
y = (x << 3) - x; // y = x * 7
y <<= 4; // y *= 16 for rounding
while(y) // until nothing significant
q += y; // add (effectively) binary 0.000111
y >>= 6; // realign
q >>= (4 + 6); // the 4 bits significance + recurrence
d = x / 9; // the true answer
if (d != q)
printf ("%d / 9 = %d (%d)\n", x, q, d); // print any errors
err++;
printf ("Errors: %d\n", err);
return 0;
【讨论】:
在二进制中,即 1/1001 = 0.000111000111000111 重复出现。没有得到这个。哦,明白了。基本上 1/9 是 1/1001。.
之后的第一个二进制表示二分之一,下一个四分之一,等等。所以这是 1/16 + 1/32 + 1/64 + 等等。前 6 位 (点之后)等于 0.109375 十进制,所以你可以看到它正在收敛到 0.111111 循环小数。
很好的逻辑。我认为 i>= 6; // 重新对齐 z += y; // 添加(有效)二进制 0.000111 我也知道为什么要添加 "z >>= 6; // align" 吗?
@newbie_old 谢谢。两点 1) 而不是for(i ...)
循环,使用while(y)
会更干净,因为当y
已转移到0
时,继续没有意义。 2)循环后z >>= 6;
的原因是因为循环内的两条指令应该是相反的:在添加到z
之前移位y
。我这样做是为了保持重要性。
你能解释一下“保持意义”是什么意思吗?【参考方案2】:
这是一个深受Hacker's Delight 启发的解决方案,它真正只使用位移位:
def divu9(n):
q = n - (n >> 3)
q = q + (q >> 6)
q = q + (q>>12) + (q>>24); q = q >> 3
r = n - (((q << 2) << 1) + q)
return q + ((r + 7) >> 4)
#return q + (r > 8)
【讨论】:
检查我提供的链接。该章节可免费下载,值得一读。【参考方案3】:看到这个答案:https://***.com/a/11694778/4907651
除了除数是 3 之外,您正在寻找的正是您想要的。
编辑:解释
我将用简单的+
替换add
函数,因为您正在寻找不使用*
或/
的解决方案。
在这个解释中,我们假设我们除以 3。
另外,我假设您知道如何将十进制转换为二进制,反之亦然。
int divideby3 (int num)
int sum = 0;
while (num > 3)
sum += (num >> 2);
num = (num >> 2) + (num & 3);
if (num == 3)
sum += 1;
return sum;
这种方法使用位运算符:
按位与:&
。
按位左移:<<
。将二进制值左移。
按位右移:>>
。将二进制值右移。
按位异或:^
第一个条件(num > 3)
是这样,因为除数是3。在你的情况下,除数是9,所以当你使用它时,条件必须是(num > 9)
。
假设我们要除的数是 6。
在二进制中,6 表示为000110
。
现在,我们进入while (num > 3)
循环。第一条语句将sum
(初始化为0)添加到num >> 2
。
num >> 2
做了什么:
二进制初始数字:
00000000 00000110
按位移位后:
00000000 00000001 i.e. 1 in decimal
添加num >> 2
后的sum
是1
。
由于我们知道 num >> 2
等于 1,我们将其添加到 num & 3
。
二进制初始编号:
00000000 00000110
3 二进制:
00000000 00000011
对于表达式a & b
的结果中的每个位位置,如果两个操作数都包含1,则该位为1,否则为0
num & 3
的结果:00000000 00000010 i.e. 2 in decimal
num = (num >> 2) + (num & 3)
之后的num
等于 1 + 2
= 3
现在,由于 num
等于 3,我们进入 if (num==3)
循环。
然后我们将 sum 加 1,然后返回值。 sum
的这个值就是商。
如预期的那样,返回值为 2。
希望这不是一个可怕的解释。
【讨论】:
然后重复 --> 除以 9。 我没看懂解释。我已经读了100遍了,如果你能解释一下,我可以把它作为正确答案。 @newbie_old 这里是一个解释。如果我解释的不是很清楚,请告诉我。我会详细说明。【参考方案4】:创建一个循环,每一步你都应该减去N-9 ..
然后(N-9)-9
.. 直到N<9 OR N=0
并且每一个减法你都要计算步骤例如:36/9 36-9=27 cmpt (1) 27-9=18 cmpt(2) 18-9=9 cmpt(3) 9-9=0 cmpt (4)
所以36/9= 4
【讨论】:
【参考方案5】:这个http://en.wikipedia.org/wiki/Ancient_Egyptian_multiplication 算法可以在log(n) 时间内只使用减法和二进制移位来完成。然而,据我所知,最先进的硬件已经在使用这个,甚至是更好的算法。因此,我认为您无能为力(假设性能是您的目标),除非您可以以某种方式完全避免除法或更改用例以便您可以除以 2 的幂,因为这些有一些技巧案例。
【讨论】:
【参考方案6】:如果不允许乘法/除法,则剩下的就是加法/减法。除以数字显示除数包含被除数的次数。您可以使用它作为回报:您可以从原始值中减去该数字多少次?
divisor = 85;
dividend = 9;
remaining = divisor;
result = 0;
while (remaining >= dividend)
remaining -= dividend;
result++;
std::cout << divisor << " / " << dividend << " = " << result;
【讨论】:
【参考方案7】:如果需要除正数,可以使用如下函数:
unsigned int divideBy9(unsigned int num)
unsigned int result = 0;
while (num >= 9)
result += 1;
num -= 9;
return result;
如果是负数,可以使用类似的方法。
希望这会有所帮助!
【讨论】:
以上是关于除以 9 而不使用除法或乘法运算符的主要内容,如果未能解决你的问题,请参考以下文章