Как добавить два числа, не используя ++ или + или другой арифметический оператор

Волшебство все, кажется, находится в

visitortime.getTimezoneOffset()

, Это прохладно, я не знал об этом. Делает это работает в Internet  Проводник, и т.д.? Оттуда необходимо быть в состоянии использовать JavaScript для Ajax, установить cookie, безотносительно. Я, вероятно, пошел бы путем cookie сам.

необходимо будет позволить пользователю изменять его все же. Мы пытались использовать геолокацию (через maxmind), чтобы сделать это только что, и было неправильно обоснованно часто - достаточно сделать его не стоящим выполнения, таким образом, мы просто позволяем пользователю установить его в их профиле и показываем уведомление пользователям, которые еще не установили их.

52
задан Peter Mortensen 23 August 2011 в 03:00
поделиться

11 ответов

Это то, что у меня есть написано некоторое время назад для развлечения. Он использует представление с дополнением до двух и реализует сложение с использованием повторяющихся сдвигов с битом переноса, реализуя другие операторы в основном в терминах сложения.

#include <stdlib.h> /* atoi() */
#include <stdio.h>  /* (f)printf */
#include <assert.h> /* assert() */

int add(int x, int y) {
    int carry = 0;
    int result = 0;
    int i;

    for(i = 0; i < 32; ++i) {
        int a = (x >> i) & 1;
        int b = (y >> i) & 1;
        result |= ((a ^ b) ^ carry) << i;
        carry = (a & b) | (b & carry) | (carry & a);
    }

    return result;
}

int negate(int x) {
    return add(~x, 1);
}

int subtract(int x, int y) {
    return add(x, negate(y));
}

int is_even(int n) {
    return !(n & 1);
}

int divide_by_two(int n) {
    return n >> 1;
}

int multiply_by_two(int n) {
    return n << 1;
}

int multiply(int x, int y) {
    int result = 0;

    if(x < 0 && y < 0) {
        return multiply(negate(x), negate(y));
    }

    if(x >= 0 && y < 0) {
        return multiply(y, x);
    }

    while(y > 0) {
        if(is_even(y)) {
            x = multiply_by_two(x);
            y = divide_by_two(y);
        } else {
            result = add(result, x);
            y = add(y, -1);
        }
    }

    return result;
}

int main(int argc, char **argv) {
    int from = -100, to = 100;
    int i, j;

    for(i = from; i <= to; ++i) {
        assert(0 - i == negate(i));
        assert(((i % 2) == 0) == is_even(i));
        assert(i * 2 == multiply_by_two(i));
        if(is_even(i)) {
            assert(i / 2 == divide_by_two(i));
        }
    }

    for(i = from; i <= to; ++i) {
        for(j = from; j <= to; ++j) {
            assert(i + j == add(i, j));
            assert(i - j == subtract(i, j));
            assert(i * j == multiply(i, j));
        }
    }

    return 0;
}
96
ответ дан 7 November 2019 в 08:57
поделиться

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

В C #:

static uint JokeAdder(uint a, uint b)
{
    string result = string.Format(string.Format("{{0,{0}}}{{1,{1}}}", a, b), null, null);
    return result.Length;
}

В C, используя stdio (замените snprintf на _snprintf в компиляторах Microsoft):

#include <stdio.h>
unsigned int JokeAdder(unsigned int a, unsigned int b)
{
    return snprintf(NULL, 0, "%*.*s%*.*s", a, a, "", b, b, "");
}
4
ответ дан 7 November 2019 в 08:57
поделиться

Для чисел без знака используйте тот же алгоритм сложения, который вы изучили в первом классе, но для базы 2 вместо базы 10. Пример для 3 + 2 (база 10), т.е. 11 + 10 в база 2:

   1         ‹--- carry bit
   0 1 1     ‹--- first operand (3)
 + 0 1 0     ‹--- second operand (2)
 -------
   1 0 1     ‹--- total sum (calculated in three steps)
5
ответ дан 7 November 2019 в 08:57
поделиться

Все арифметические операции разлагаются на побитовые операции, которые должны быть реализованы в электронике, с использованием логических элементов И-НЕ, И, ИЛИ и т. Д.

Состав сумматора можно увидеть здесь .

5
ответ дан 7 November 2019 в 08:57
поделиться

Следующее будет работать:

x - (-y)
0
ответ дан 7 November 2019 в 08:57
поделиться

Вы уже получили пару ответов на манипуляции с битами. Вот что-то другое.

В C, arr [ind] == * (arr + ind) . Это позволяет нам делать немного запутанные (но законные) вещи вроде int arr = {3, 1, 4, 5}; int val = 0 [arr]; .

Итак, мы можем определить пользовательскую функцию добавления (без явного использования арифметического оператора) следующим образом:

unsigned int add(unsigned int const a, unsigned int const b)
{
    /* this works b/c sizeof(char) == 1, by definition */
    char * const aPtr = (char *)a;
    return (int) &(aPtr[b]);
}

В качестве альтернативы, если мы хотим избежать этого трюка, и если арифметический оператор, который они включают в себя | , & и ^ (поэтому прямая манипуляция с битами не разрешена), мы можем сделать это через таблицу поиска:

typedef unsigned char byte;

const byte lut_add_mod_256[256][256] = { 
  { 0, 1, 2, /*...*/, 255 },
  { 1, 2, /*...*/, 255, 0 },
  { 2, /*...*/, 255, 0, 1 },
  /*...*/
  { 254, 255, 0, 1, /*...*/, 253 },
  { 255, 0, 1, /*...*/, 253, 254 },
}; 

const byte lut_add_carry_256[256][256] = {
  { 0, 0, 0, /*...*/, 0 },
  { 0, 0, /*...*/, 0, 1 },
  { 0, /*...*/, 0, 1, 1 },
  /*...*/
  { 0, 0, 1, /*...*/, 1 },
  { 0, 1, 1, /*...*/, 1 },
};

void add_byte(byte const a, byte const b, byte * const sum, byte * const carry)
{
  *sum = lut_add_mod_256[a][b];
  *carry = lut_add_carry_256[a][b];
}

unsigned int add(unsigned int a, unsigned int b)
{
  unsigned int sum;
  unsigned int carry;
  byte * const aBytes = (byte *) &a;
  byte * const bBytes = (byte *) &b;
  byte * const sumBytes = (byte *) &sum;
  byte * const carryBytes = (byte *) &carry;

  byte const test[4] = { 0x12, 0x34, 0x56, 0x78 };
  byte BYTE_0, BYTE_1, BYTE_2, BYTE_3;

  /* figure out endian-ness */
  if (0x12345678 == *(unsigned int *)test)
  {
    BYTE_0 = 3;
    BYTE_1 = 2;
    BYTE_2 = 1;
    BYTE_3 = 0;
  }
  else 
  {
    BYTE_0 = 0;
    BYTE_1 = 1;
    BYTE_2 = 2;
    BYTE_3 = 3;
  }


  /* assume 4 bytes to the unsigned int */
  add_byte(aBytes[BYTE_0], bBytes[BYTE_0], &sumBytes[BYTE_0], &carryBytes[BYTE_0]);

  add_byte(aBytes[BYTE_1], bBytes[BYTE_1], &sumBytes[BYTE_1], &carryBytes[BYTE_1]);
  if (carryBytes[BYTE_0] == 1)
  {
    if (sumBytes[BYTE_1] == 255)
    {
      sumBytes[BYTE_1] = 0;
      carryBytes[BYTE_1] = 1;
    }
    else
    {
      add_byte(sumBytes[BYTE_1], 1, &sumBytes[BYTE_1], &carryBytes[BYTE_0]);
    }
  }

  add_byte(aBytes[BYTE_2], bBytes[BYTE_2], &sumBytes[BYTE_2], &carryBytes[BYTE_2]);
  if (carryBytes[BYTE_1] == 1)
  {
    if (sumBytes[BYTE_2] == 255)
    {
      sumBytes[BYTE_2] = 0;
      carryBytes[BYTE_2] = 1;
    }
    else
    {
      add_byte(sumBytes[BYTE_2], 1, &sumBytes[BYTE_2], &carryBytes[BYTE_1]);
    }
  }

  add_byte(aBytes[BYTE_3], bBytes[BYTE_3], &sumBytes[BYTE_3], &carryBytes[BYTE_3]);
  if (carryBytes[BYTE_2] == 1)
  {
    if (sumBytes[BYTE_3] == 255)
    {
      sumBytes[BYTE_3] = 0;
      carryBytes[BYTE_3] = 1;
    }
    else
    {
      add_byte(sumBytes[BYTE_3], 1, &sumBytes[BYTE_3], &carryBytes[BYTE_2]);
    }
  }

  return sum;
}
6
ответ дан 7 November 2019 в 08:57
поделиться

Что ж, реализовать эквивалент с булевыми операторами довольно просто: вы выполняете побитовое суммирование (которое является XOR) с переносом (которое является AND). Примерно так:

int sum(int value1, int value2)
{
    int result = 0;
    int carry = 0;
    for (int mask = 1; mask != 0; mask <<= 1)
    {
        int bit1 = value1 & mask;
        int bit2 = value2 & mask;
        result |= mask & (carry ^ bit1 ^ bit2);
        carry = ((bit1 & bit2) | (bit1 & carry) | (bit2 & carry)) << 1;
    }
    return result;
}
7
ответ дан 7 November 2019 в 08:57
поделиться

Вы можете преобразовать сумматор в алгоритм. Они выполняют только побитовые операции =)

17
ответ дан 7 November 2019 в 08:57
поделиться
int Add(int a, int b)
{
    while (b)
    {
        int carry = a & b;
        a = a ^ b;
        b = carry << 1;
    }
    return a;
}
20
ответ дан 7 November 2019 в 08:57
поделиться

Или, вместо побитового подхода Джейсона, вы можете вычислить много битов параллельно - это должно работать намного быстрее с большими числами. На каждом этапе вычисляйте часть переноса и часть суммы. Вы пытаетесь добавить перенос к сумме, что может снова вызвать перенос - отсюда и цикл.

>>> def add(a, b):
    while a != 0:
        #      v carry portion| v sum portion
        a, b = ((a & b) << 1),  (a ^ b)
        print b, a
    return b

когда вы складываете 1 и 3, оба числа имеют установленный бит 1, поэтому сумма этого 1 + 1 переносится. На следующем шаге вы добавляете 2 к 2, и это дает правильную сумму четыре. Это вызывает выход

>>> add(1,3)
2 2
4 0
4

Или более сложный пример

>>> add(45, 291)
66 270
4 332
8 328
16 320
336

Изменить: Чтобы он мог легко работать со знаковыми числами, вам нужно ввести верхний предел для a и b

>>> def add(a, b):
    while a != 0:
        #      v carry portion| v sum portion
        a, b = ((a & b) << 1),  (a ^ b)
        a &= 0xFFFFFFFF
        b &= 0xFFFFFFFF
        print b, a
    return b

Попробуйте его на

add(-1, 1)

, чтобы увидеть перенос одного бита через весь диапазон и переполнение на 32 итерациях

4294967294 2
4294967292 4
4294967288 8
...
4294901760 65536
...
2147483648 2147483648
0 0
0L
51
ответ дан 7 November 2019 в 08:57
поделиться
short int ripple_adder(short int a, short int b)
{
    short int i, c, s, ai, bi;

    c = s = 0;

    for (i=0; i<16; i++)
    {
        ai = a & 1;
        bi = b & 1;

        s |= (((ai ^ bi)^c) << i);
        c = (ai & bi) | (c & (ai ^ bi));

        a >>= 1;
        b >>= 1;
    }
    s |= (c << i);
    return s;
}
1
ответ дан 7 November 2019 в 08:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: