如何将一个数除3而不使用*、/、+、-、%等运算符?

号码可以有签名,也可以没有签名。


当前回答

下面的脚本生成了一个C程序,可以在不使用运算符* / + - %的情况下解决这个问题:

#!/usr/bin/env python3

print('''#include <stdint.h>
#include <stdio.h>
const int32_t div_by_3(const int32_t input)
{
''')

for i in range(-2**31, 2**31):
    print('    if(input == %d) return %d;' % (i, i / 3))


print(r'''
    return 42; // impossible
}
int main()
{
    const int32_t number = 8;
    printf("%d / 3 = %d\n", number, div_by_3(number));
}
''')

其他回答

以下是我的解决方案:

public static int div_by_3(long a) {
    a <<= 30;
    for(int i = 2; i <= 32 ; i <<= 1) {
        a = add(a, a >> i);
    }
    return (int) (a >> 32);
}

public static long add(long a, long b) {
    long carry = (a & b) << 1;
    long sum = (a ^ b);
    return carry == 0 ? sum : add(carry, sum);
}

首先,请注意

1/3 = 1/4 + 1/16 + 1/64 + ...

现在,剩下的很简单!

a/3 = a * 1/3  
a/3 = a * (1/4 + 1/16 + 1/64 + ...)
a/3 = a/4 + a/16 + 1/64 + ...
a/3 = a >> 2 + a >> 4 + a >> 6 + ...

现在我们要做的就是把a的这些位移位值加在一起!哦!但是我们不能做加法,所以我们必须使用位操作符来编写一个加法函数!如果您熟悉逐位操作符,那么我的解决方案应该看起来相当简单……但以防你不懂,我会在最后讲一个例子。

另一件需要注意的事情是,首先我左移30!这是为了确保分数不会四舍五入。

11 + 6

1011 + 0110  
sum = 1011 ^ 0110 = 1101  
carry = (1011 & 0110) << 1 = 0010 << 1 = 0100  
Now you recurse!

1101 + 0100  
sum = 1101 ^ 0100 = 1001  
carry = (1101 & 0100) << 1 = 0100 << 1 = 1000  
Again!

1001 + 1000  
sum = 1001 ^ 1000 = 0001  
carry = (1001 & 1000) << 1 = 1000 << 1 = 10000  
One last time!

0001 + 10000
sum = 0001 ^ 10000 = 10001 = 17  
carry = (0001 & 10000) << 1 = 0

Done!

这就是你小时候学过的简单加法!

111
 1011
+0110
-----
10001

这个实现失败了,因为我们不能把方程的所有项相加:

a / 3 = a/4 + a/4^2 + a/4^3 + ... + a/4^i + ... = f(a, i) + a * 1/3 * 1/4^i
f(a, i) = a/4 + a/4^2 + ... + a/4^i

假设div_by_3(a) = x的结果,则x <= floor(f(a, i)) < a / 3。当a = 3k时,我们得到错误的答案。

这是我小时候爷爷教我的一个方法。它需要+和/运算符,但计算起来很简单。

把每个数字相加,然后看看它是否是3的倍数。

但这种方法适用于大于12的数字。

例如:36岁,

3+6=9,是3的倍数。

42,

4+2=6,是3的倍数。

通过使用eval和字符串连接来在“幕后”使用/操作符是欺骗吗?

例如,在Javacript中,您可以这样做

function div3 (n) {
    var div = String.fromCharCode(47);
    return eval([n, div, 3].join(""));
}

下面的脚本生成了一个C程序,可以在不使用运算符* / + - %的情况下解决这个问题:

#!/usr/bin/env python3

print('''#include <stdint.h>
#include <stdio.h>
const int32_t div_by_3(const int32_t input)
{
''')

for i in range(-2**31, 2**31):
    print('    if(input == %d) return %d;' % (i, i / 3))


print(r'''
    return 42; // impossible
}
int main()
{
    const int32_t number = 8;
    printf("%d / 3 = %d\n", number, div_by_3(number));
}
''')

第一:

x/3 = (x/4) / (1-1/4)

然后求x/(1 - y)

x/(1-1/y)
  = x * (1+y) / (1-y^2)
  = x * (1+y) * (1+y^2) / (1-y^4)
  = ...
  = x * (1+y) * (1+y^2) * (1+y^4) * ... * (1+y^(2^i)) / (1-y^(2^(i+i))
  = x * (1+y) * (1+y^2) * (1+y^4) * ... * (1+y^(2^i))

y = 1/4:

int div3(int x) {
    x <<= 6;    // need more precise
    x += x>>2;  // x = x * (1+(1/2)^2)
    x += x>>4;  // x = x * (1+(1/2)^4)
    x += x>>8;  // x = x * (1+(1/2)^8)
    x += x>>16; // x = x * (1+(1/2)^16)
    return (x+1)>>8; // as (1-(1/2)^32) very near 1,
                     // we plus 1 instead of div (1-(1/2)^32)
}

虽然它使用了+,但有人已经实现了按位操作的add。