Как добавить два числа без использования ++ или + или другого арифметического оператора
Как добавить два числа без использования ++ или + или любого другого арифметического оператора?
Это был вопрос, заданный давным-давно в одном интервью кампуса. Во всяком случае, сегодня кто-то задал вопрос относительно некоторых бит-манипуляций, и в ответах красивый quide Стэнфорд немного вертится был передан. Я потратил некоторое время на его изучение и подумал, что на самом деле может быть ответ на этот вопрос. Я не знаю, я не мог найти ни одного. Делает ответ существует?
20 ответов:
Это то, что я написал некоторое время назад для удовольствия. Он использует дополнение представление и реализует сложение с использованием повторяющихся сдвигов с битом переноса, реализуя другие операторы в основном с точки зрения сложения.
#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; }
или, вместо побитового подхода Джейсона, вы можете вычислить много битов параллельно - это должно работать намного быстрее с большими числами. В каждом шаге выясните часть переноса и часть, которая является суммой. Вы пытаетесь добавить перенос к сумме, которая может вызвать перенос снова - следовательно, цикл.
>>> 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 336Edit: Чтобы он легко работал на подписанных числах, вам нужно ввести верхний предел на 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
вы можете преобразовать сумматор схемы в алгоритм. Они делают только побитовые операции =)
ну, реализовать эквивалент с булевыми операторами довольно просто: вы делаете побитовую сумму (которая является 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; }
вы уже получили несколько ответов на манипуляции. Здесь что-то другое.
В 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 *) ∑ 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; }
все арифметические операции разложить на побитовые операции должны быть реализованы в электронике, с использованием флэш-памяти NAND, и, или, и т. д. ворота.
для беззнаковых чисел используйте тот же алгоритм сложения, что и в первом классе, но для базы 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)
Если вы чувствуете себя комично, всегда есть этот впечатляюще ужасный подход для добавления двух (относительно небольших) целых чисел без знака. Нет арифметических операторов нигде в коде.
В 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, ""); }
здесь-это компактное решение с. Иногда рекурсия более удобочитаема, чем циклы.
int add(int a, int b){ if (b == 0) return a; return add(a ^ b, (a & b) << 1); }
#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; }
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; }
## to add or subtract without using '+' and '-' ## #include<stdio.h> #include<conio.h> #include<process.h> void main() { int sub,a,b,carry,temp,c,d; clrscr(); printf("enter a and b:"); scanf("%d%d",&a,&b); c=a; d=b; while(b) { carry=a&b; a=a^b; b=carry<<1; } printf("add(%d,%d):%d\n",c,d,a); temp=~d+1; //take 2's complement of b and add it with a sub=c+temp; printf("diff(%d,%d):%d\n",c,d,temp); getch(); }
Это можно сделать рекурсивно:
int add_without_arithm_recursively(int a, int b) { if (b == 0) return a; int sum = a ^ b; // add without carrying int carry = (a & b) << 1; // carry, but don’t add return add_without_arithm_recursively(sum, carry); // recurse }или итерационно:
int add_without_arithm_iteratively(int a, int b) { int sum, carry; do { sum = a ^ b; // add without carrying carry = (a & b) << 1; // carry, but don’t add a = sum; b = carry; } while (b != 0); return a; }
код для реализации сложения, умножения без использования
+,*оператор; для вычитания передайте Дополнение 1 +1 числа кaddфункции#include<stdio.h> unsigned int add(unsigned int x,unsigned int y) { int carry=0; while (y != 0) { carry = x & y; x = x ^ y; y = carry << 1; } return x; } int multiply(int a,int b) { int res=0; int i=0; int large= a>b ? a :b ; int small= a<b ? a :b ; for(i=0;i<small;i++) { res = add(large,res); } return res; } int main() { printf("Sum :: %u,Multiply is :: %d",add(7,15),multiply(111,111)); return 0; }
вопрос спрашивает, как добавить два числа, поэтому я не понимаю, почему все решения предлагают добавление двух целых чисел? Что делать, если эти два числа были поплавки т. е.
2.3 + 1.8Они также не считаются числами? Либо вопрос должен быть пересмотрен, либо ответы.для поплавков я считаю, что числа должны быть разбиты на их компоненты, т. е.
2.3 = 2 + 0.3тут0.3должно быть преобразовано в целочисленное представление путем умножения с его показателем степени, т. е.0.3 = 3 * 10^-1сделайте то же самое для другого числа, а затем добавьте целочисленный сегмент, используя один из методов сдвига битов, приведенных в качестве решения выше ситуаций обработки для переноса в расположение единичных цифр, т. е.2.7 + 3.3 = 6.0 = 2+3+0.7+0.3 = 2 + 3 + 7x10^-1 + 3x10^-1 = 2 + 3 + 10^10^-1(это может быть обработано как два отдельных дополнения2+3=5а то5+1=6)
int add_without_arithmatic(int a, int b) { int sum; char *p; p = (char *)a; sum = (int)&p[b]; printf("\nSum : %d",sum); }
С учетом ответов выше, это может быть сделано в одной строке кода:
int add(int a, int b) { return (b == 0) ? a : add(a ^ b, (a & b) << 1); }
Я думаю, что этот код будет полезен для добавления двух чисел без оператора plus
#include<stdio.h> int main() { int a, b, c; printf("enter two no. : "); scanf("%d%d", &a, &b); c = (a - ~b - 1); printf("%d\n", c); return 0; }
Comments