我和一个朋友在脑筋急转弯中来回走动,我不知道如何解决这个问题。我的假设是使用一些位运算符是可能的,但不确定。
24 回答
在 C 中,使用位运算符:
#include<stdio.h>
int add(int x, int y) {
int a, b;
do {
a = x & y;
b = x ^ y;
x = a << 1;
y = b;
} while (a);
return b;
}
int main( void ){
printf( "2 + 3 = %d", add(2,3));
return 0;
}
XOR ( x ^ y
) 是不带进位的加法。 (x & y)
是每个位的进位。 (x & y) << 1
是每个位的进位。
循环不断添加进位,直到所有位的进位为零。
int add(int a, int b) {
const char *c=0;
return &(&c[a])[b];
}
没有+对吗?
int add(int a, int b)
{
return -(-a) - (-b);
}
定义“最佳”。这是一个python版本:
len(range(x)+range(y))
+
执行列表连接,而不是添加。
CMS 的 add() 函数很漂亮。它不应该被一元否定所玷污(非按位运算,相当于使用加法:-y==(~y)+1)。所以这是一个使用相同的仅按位设计的减法函数:
int sub(int x, int y) {
unsigned a, b;
do {
a = ~x & y;
b = x ^ y;
x = b;
y = a << 1;
} while (a);
return b;
}
请注意,这适用于称为波纹进位加法器的加法器,它可以工作,但性能不佳。大多数内置于硬件中的二进制加法器都是一种快速加法器,例如进位预读加法器。
如果将 carry_in 设置为 0,我的波纹进位加法器适用于无符号整数和 2 的补码整数,如果将 carry_in 设置为 1,则适用于 1 的补码整数。我还添加了标志以显示加法时的下溢或溢出。
#define BIT_LEN 32
#define ADD_OK 0
#define ADD_UNDERFLOW 1
#define ADD_OVERFLOW 2
int ripple_add(int a, int b, char carry_in, char* flags) {
int result = 0;
int current_bit_position = 0;
char a_bit = 0, b_bit = 0, result_bit = 0;
while ((a || b) && current_bit_position < BIT_LEN) {
a_bit = a & 1;
b_bit = b & 1;
result_bit = (a_bit ^ b_bit ^ carry_in);
result |= result_bit << current_bit_position++;
carry_in = (a_bit & b_bit) | (a_bit & carry_in) | (b_bit & carry_in);
a >>= 1;
b >>= 1;
}
if (current_bit_position < BIT_LEN) {
*flags = ADD_OK;
}
else if (a_bit & b_bit & ~result_bit) {
*flags = ADD_UNDERFLOW;
}
else if (~a_bit & ~b_bit & result_bit) {
*flags = ADD_OVERFLOW;
}
else {
*flags = ADD_OK;
}
return result;
}
使用按位运算符的 Java 解决方案:
// Recursive solution
public static int addR(int x, int y) {
if (y == 0) return x;
int sum = x ^ y; //SUM of two integer is X XOR Y
int carry = (x & y) << 1; //CARRY of two integer is X AND Y
return addR(sum, carry);
}
//Iterative solution
public static int addI(int x, int y) {
while (y != 0) {
int carry = (x & y); //CARRY is AND of two bits
x = x ^ y; //SUM of two bits is X XOR Y
y = carry << 1; //shifts carry to 1 bit to calculate sum
}
return x;
}
基于 Go 的解决方案
func add(a int, b int) int {
for {
carry := (a & b) << 1
a = a ^ b
b = carry
if b == 0 {
break
}
}
return a
}
相同的解决方案可以在 Python 中实现如下,但是在 Python 中数字表示存在一些问题,Python 有超过 32 位的整数。所以我们将使用掩码来获取最后 32 位。
例如:如果我们不使用掩码,我们将不会得到数字的结果 (-1,1)
def add(a,b):
mask = 0xffffffff
while b & mask:
carry = a & b
a = a ^ b
b = carry << 1
return (a & mask)
为什么不像第二个数字一样频繁地增加第一个数字呢?
ADD 在汇编程序中作为单个指令而不是按位操作的某种组合实现的原因是它很难做到。您必须担心从给定的低位到下一个高位的进位。这是机器在硬件中快速完成的事情,但即使使用 C,您也无法在软件中快速完成。
这是一个可移植的单行三元递归解决方案。
int add(int x, int y) {
return y == 0 ? x : add(x ^ y, (x & y) << 1);
}
我在编码面试中将此视为问题 18.1。我的蟒蛇解决方案:
def foo(a, b):
"""iterate through a and b, count iteration via a list, check len"""
x = []
for i in range(a):
x.append(a)
for i in range(b):
x.append(b)
print len(x)
该方法使用迭代,因此时间复杂度不是最优的。我相信最好的方法是使用按位运算在较低级别上工作。
在 python 中使用按位运算符:
def sum_no_arithmetic_operators(x,y):
while True:
carry = x & y
x = x ^ y
y = carry << 1
if y == 0:
break
return x
添加两个整数并不难;网上有很多二进制加法的例子。
一个更具挑战性的问题是浮点数!在http://pages.cs.wisc.edu/~smoler/x86text/lect.notes/arith.flpt.html有一个例子
您可以使用位移位和 AND 操作来做到这一点。
#include <stdio.h>
int main()
{
unsigned int x = 3, y = 1, sum, carry;
sum = x ^ y; // Ex - OR x and y
carry = x & y; // AND x and y
while (carry != 0) {
carry = carry << 1; // left shift the carry
x = sum; // initialize x as sum
y = carry; // initialize y as carry
sum = x ^ y; // sum is calculated
carry = x & y; /* carry is calculated, the loop condition is
evaluated and the process is repeated until
carry is equal to 0.
*/
}
printf("%d\n", sum); // the program will print 4
return 0;
}
以与我们在纸上进行二进制加法相同的方式实现。
int add(int x, int y)
{
int t1_set, t2_set;
int carry = 0;
int result = 0;
int mask = 0x1;
while (mask != 0) {
t1_set = x & mask;
t2_set = y & mask;
if (carry) {
if (!t1_set && !t2_set) {
carry = 0;
result |= mask;
} else if (t1_set && t2_set) {
result |= mask;
}
} else {
if ((t1_set && !t2_set) || (!t1_set && t2_set)) {
result |= mask;
} else if (t1_set && t2_set) {
carry = 1;
}
}
mask <<= 1;
}
return (result);
}
速度改进如下:
int add_better (int x, int y)
{
int b1_set, b2_set;
int mask = 0x1;
int result = 0;
int carry = 0;
while (mask != 0) {
b1_set = x & mask ? 1 : 0;
b2_set = y & mask ? 1 : 0;
if ( (b1_set ^ b2_set) ^ carry)
result |= mask;
carry = (b1_set & b2_set) | (b1_set & carry) | (b2_set & carry);
mask <<= 1;
}
return (result);
}
我自己在 C# 中解决了这个问题,但无法通过所有测试用例。然后我遇到了这个。
这是 C# 6 中的一个实现:
public int Sum(int a, int b) => b != 0 ? Sum(a ^ b, (a & b) << 1) : a;
这是我在 Python 上的实现。当我们知道字节数(或位数)时,它运行良好。
def summ(a, b):
#for 4 bytes(or 4*8 bits)
max_num = 0xFFFFFFFF
while a != 0:
a, b = ((a & b) << 1), (a ^ b)
if a > max_num:
b = (b&max_num)
break
return b
如果输入符号相反,则投票最多的答案将不起作用。然而,以下将。我在一个地方作弊,但只是为了保持代码有点干净。欢迎任何改进建议
def add(x, y):
if (x >= 0 and y >= 0) or (x < 0 and y < 0):
return _add(x, y)
else:
return __add(x, y)
def _add(x, y):
if y == 0:
return x
else:
return _add((x ^ y), ((x & y) << 1))
def __add(x, y):
if x < 0 < y:
x = _add(~x, 1)
if x > y:
diff = -sub(x, y)
else:
diff = sub(y, x)
return diff
elif y < 0 < x:
y = _add(~y, 1)
if y > x:
diff = -sub(y, x)
else:
diff = sub(y, x)
return diff
else:
raise ValueError("Invalid Input")
def sub(x, y):
if y > x:
raise ValueError('y must be less than x')
while y > 0:
b = ~x & y
x ^= y
y = b << 1
return x
这是 C++ 中的解决方案,您可以在我的 github 上找到它:https ://github.com/CrispenGari/Add-Without-Integers-without-operators/blob/master/main.cpp
int add(int a, int b){
while(b!=0){
int sum = a^b; // add without carrying
int carry = (a&b)<<1; // carrying without adding
a= sum;
b= carry;
}
return a;
}
// the function can be writen as follows :
int add(int a, int b){
if(b==0){
return a; // any number plus 0 = that number simple!
}
int sum = a ^ b;// adding without carrying;
int carry = (a & b)<<1; // carry, without adding
return add(sum, carry);
}
This can be done using Half Adder.
Half Adder is method to find sum of numbers with single bit.
A B SUM CARRY A & B A ^ B
0 0 0 0 0 0
0 1 1 0 0 1
1 0 1 0 0 1
1 1 0 1 0 0
We can observe here that SUM = A ^ B and CARRY = A & B
We know CARRY is always added at 1 left position from where it was
generated.
so now add ( CARRY << 1 ) in SUM, and repeat this process until we get
Carry 0.
int Addition( int a, int b)
{
if(B==0)
return A;
Addition( A ^ B, (A & B) <<1 )
}
let's add 7 (0111) and 3 (0011) answer will be 10 (1010)
- A = 0100 和 B = 0110
- A = 0010 和 B = 1000
- A = 1010 和 B = 0000 最终答案是 A。
我在 Swift 中实现了这个,我相信有人会从中受益
var a = 3
var b = 5
var sum = 0
var carry = 0
while (b != 0) {
sum = a ^ b
carry = a & b
a = sum
b = carry << 1
}
print (sum)
Python代码:(1)
add = lambda a,b : -(-a)-(-b)
使用带有“-”运算符的 lambda 函数
(2)
add= lambda a,b : len(list(map(lambda x:x,(i for i in range(-a,b)))))