How to add two numbers without using ++ or + or another arithmetic operator

后端 未结 21 1879
南笙
南笙 2020-11-27 10:48

How do I add two numbers without using ++ or + or any other arithmetic operator?

It was a question asked a long time ago in some campus interview. Anyway, today some

相关标签:
21条回答
  • 2020-11-27 11:41

    Or, rather than Jason's bitwise approach, you can calculate many bits in parallel - this should run much faster with large numbers. In each step figure out the carry part and the part that is sum. You attempt to add the carry to the sum, which could cause carry again - hence the loop.

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

    when you add 1 and 3, both numbers have the 1 bit set, so the sum of that 1+1 carries. The next step you add 2 to 2 and that carries into the correct sum four. That causes an exit

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

    Or a more complex example

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

    Edit: For it to work easily on signed numbers you need to introduce an upper limit on a and 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
    

    Try it on

    add(-1, 1)
    

    to see a single bit carry up through the entire range and overflow over 32 iterations

    4294967294 2
    4294967292 4
    4294967288 8
    ...
    4294901760 65536
    ...
    2147483648 2147483648
    0 0
    0L
    
    0 讨论(0)
  • 2020-11-27 11:42

    You've already gotten a couple bit manipulation answers. Here's something different.

    In C, arr[ind] == *(arr + ind). This lets us do slightly confusing (but legal) things like int arr = { 3, 1, 4, 5 }; int val = 0[arr];.

    So we can define a custom add function (without explicit use of an arithmetic operator) thusly:

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

    Alternately, if we want to avoid this trick, and if by arithmetic operator they include |, &, and ^ (so direct bit manipulation is not allowed) , we can do it via lookup table:

    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;
    }
    
    0 讨论(0)
  • 2020-11-27 11:42

    The question asks how to add two numbers so I don't understand why all the solutions offers the addition of two integers? What if the two numbers were floats i.e. 2.3 + 1.8 are they also not considered numbers? Either the question needs to be revised or the answers.

    For floats I believe the numbers should be broken into their components i.e. 2.3 = 2 + 0.3 then the 0.3 should be converted to an integer representation by multiplying with its exponent factor i.e 0.3 = 3 * 10^-1 do the same for the other number and then add the integer segment using one of the bit shift methods given as a solution above handling situations for carry over to the unit digits location i.e. 2.7 + 3.3 = 6.0 = 2+3+0.7+0.3 = 2 + 3 + 7x10^-1 + 3x10^-1 = 2 + 3 + 10^10^-1 (this can be handled as two separate additions 2+3=5 and then 5+1=6)

    0 讨论(0)
提交回复
热议问题