Как лучше всего добавить два числа без использования оператора +? - PullRequest
23 голосов
/ 13 декабря 2008

Мы с другом возвращаемся назад и вперед с дразнилками, и я понятия не имею, как решить этот вопрос. Я предполагаю, что это возможно с некоторыми побитовыми операторами, но не уверен.

Ответы [ 20 ]

40 голосов
/ 13 декабря 2008

В 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 - это перенос каждого бита.

Цикл продолжает добавлять переносы, пока перенос для всех битов не станет равным нулю.

22 голосов
/ 14 декабря 2008
int add(int a, int b) {
   const char *c=0;
   return &(&c[a])[b];
}
9 голосов
/ 13 декабря 2008

Нет + верно?

int add(int a, int b) 
{
   return -(-a) - (-b);
}
5 голосов
/ 13 декабря 2008

Определить «лучший». Вот версия Python:

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

+ выполняет конкатенацию списка, а не сложение.

5 голосов
/ 22 февраля 2010

Функция add () CMS прекрасна. Он не должен быть запятнан унарным отрицанием (небитовая операция, равносильная использованию сложения: -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;
}
4 голосов
/ 13 декабря 2008

Обратите внимание, что это будет для сумматора, известного как сумматор с пульсациями , который работает, но не работает оптимально. Большинство двоичных сумматоров, встроенных в аппаратные средства, представляют собой быструю сумматорную форму, такую ​​как сумматор с упреждением .

Мой сумматор ripple-carry работает как для целых чисел без знака, так и для целых чисел дополнения 2, если вы установили для значение carry_in значение 0, и для целых чисел дополнения 1, если для значения carry_in установлено значение 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;
}
4 голосов
/ 26 февраля 2017

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;
}
4 голосов
/ 13 декабря 2008

Чит. Вы можете отменить число и вычесть его из первого:)

В противном случае посмотрите, как работает двоичный сумматор. :)

РЕДАКТИРОВАТЬ: Ах, видел ваш комментарий после того, как я опубликовал.

Подробности бинарного сложения: здесь .

2 голосов
/ 13 декабря 2008

Причина, по которой ADD реализован в ассемблере как отдельная инструкция, а не как некоторая комбинация побитовых операций, заключается в том, что это трудно сделать. Вы должны беспокоиться о переносах с данного бита младшего разряда на следующий бит старшего разряда. Это то, что машины делают быстро на оборудовании, но даже с C вы не можете делать это быстро в программном обеспечении.

2 голосов
/ 13 декабря 2008

Почему бы просто не увеличить первый номер так часто, как второй номер?

...