除以 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 &gt;&gt;= 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; 

这种方法使用位运算符:

按位与:&amp;。 按位左移:&lt;&lt;。将二进制值左移。 按位右移:&gt;&gt;。将二进制值右移。 按位异或:^

第一个条件(num &gt; 3)是这样,因为除数是3。在你的情况下,除数是9,所以当你使用它时,条件必须是(num &gt; 9)

假设我们要除的数是 6。

在二进制中,6 表示为000110

现在,我们进入while (num &gt; 3) 循环。第一条语句将sum(初始化为0)添加到num &gt;&gt; 2

num &gt;&gt; 2 做了什么:

二进制初始数字:00000000 00000110

按位移位后:00000000 00000001 i.e. 1 in decimal

添加num &gt;&gt; 2后的sum1

由于我们知道 num &gt;&gt; 2 等于 1,我们将其添加到 num &amp; 3

二进制初始编号:00000000 00000110

3 二进制:00000000 00000011

对于表达式a &amp; b的结果中的每个位位置,如果两个操作数都包含1,则该位为1,否则为0

num &amp; 3的结果:00000000 00000010 i.e. 2 in decimal

num = (num &gt;&gt; 2) + (num &amp; 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&lt;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 而不使用除法或乘法运算符的主要内容,如果未能解决你的问题,请参考以下文章

Excel怎么进行乘法和除法

请问怎样用加法-移位实现定点乘除法?

运算符

MySQL运算符

Python运算符

在java中不使用乘法,除法和mod运算符将两个整数相除