What is the best way to add two numbers without using the + operator?

本小妞迷上赌 提交于 2019-11-26 20:21:46
CMS

In C, with bitwise operators:

#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) is addition without carry. (x & y) is the carry-out from each bit. (x & y) << 1 is the carry-in to each bit.

The loop keeps adding the carries until the carry is zero for all bits.

ackb
int add(int a, int b) {
   const char *c=0;
   return &(&c[a])[b];
}

No + right?

int add(int a, int b) 
{
   return -(-a) - (-b);
}

CMS's add() function is beautiful. It should not be sullied by unary negation (a non-bitwise operation, tantamount to using addition: -y==(~y)+1). So here's a subtraction function using the same bitwise-only design:

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;
}
Charlie Martin

Define "best". Here's a python version:

len(range(x)+range(y))

The + performs list concatenation, not addition.

Java solution with bitwise operators:

// 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;
}

Cheat. You could negate the number and subtract it from the first :)

Failing that, look up how a binary adder works. :)

EDIT: Ah, saw your comment after I posted.

Details of binary addition are here.

Lara Dougan

Note, this would be for an adder known as a ripple-carry adder, which works, but does not perform optimally. Most binary adders built into hardware are a form of fast adder such as a carry-look-ahead adder.

My ripple-carry adder works for both unsigned and 2's complement integers if you set carry_in to 0, and 1's complement integers if carry_in is set to 1. I also added flags to show underflow or overflow on the addition.

#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;
}

Why not just incremet the first number as often, as the second number?

The reason ADD is implememted in assembler as a single instruction, rather than as some combination of bitwise operations, is that it is hard to do. You have to worry about the carries from a given low order bit to the next higher order bit. This is stuff that the machines do in hardware fast, but that even with C, you can't do in software fast.

Adding two integers is not that difficult; there are many examples of binary addition online.

A more challenging problem is floating point numbers! There's an example at http://pages.cs.wisc.edu/~smoler/x86text/lect.notes/arith.flpt.html

In python using bitwise operators:

def sum_no_arithmetic_operators(x,y):
    while True:
        carry = x & y
        x = x ^ y
        y = carry << 1
        if y == 0:
            break
    return x

Was working on this problem myself in C# and couldn't get all test cases to pass. I then ran across this.

Here is an implementation in C# 6:

public int Sum(int a, int b) => b != 0 ? Sum(a ^ b, (a & b) << 1) : a;
user3922199

Implemented in same way as we might do binary addition on paper.

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);
}

Improved for speed would be below::

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);
}
James

I saw this as problem 18.1 in the coding interview. My python solution:

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)

This method uses iteration, so the time complexity isn't optimal. I believe the best way is to work at a lower level with bitwise operations.

Konstantin Purtov

It is my implementation on Python. It works well, when we know the number of bytes(or bits).

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
kyle k

You can do it using bit-shifting and the AND operation.

#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;
}
lalatnayak

The most voted answer will not work if the inputs are of opposite sign. The following however will. I have cheated at one place, but only to keep the code a bit clean. Any suggestions for improvement welcome

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

Here's a portable one-line ternary and recursive solution.

int add(int x, int y) {
    return y == 0 ? x : add(x ^ y, (x & y) << 1);
}

Python codes: (1)

add = lambda a,b : -(-a)-(-b)

use lambda function with '-' operator

(2)

add= lambda a,b : len(list(map(lambda x:x,(i for i in range(-a,b)))))
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!