13

How can I subtract two integers in C without the - operator?

SyncMaster
  • 9,754
  • 34
  • 94
  • 137
  • Why would you want to do this, or is it homework? – Toon Krijthe Mar 31 '09 at 07:34
  • What are you subtracting? integers, floats? – dan gibson Mar 31 '09 at 07:34
  • no its not a homework.. i faced this question in an interview and thought of asking it here – SyncMaster Mar 31 '09 at 07:36
  • Possible duplicate of [Subtracting two numbers without using '-' operator](http://stackoverflow.com/questions/3430651/subtracting-two-numbers-without-using-operator) – MD XF Feb 21 '17 at 16:48
  • @MDXF Can´t be duplicate. This question is older. If, then the linked question is a duplicate. But in my opinion it isn´t because the OP at linked question had asked for an issue in his/her code, not for ways to accomplish subtracting without `-`. Title seems to be misleading a bit. – RobertS supports Monica Cellio May 30 '20 at 09:02

17 Answers17

19
int a = 34;
int b = 50;

You can convert b to negative value using negation and adding 1:

int c = a + (~b + 1);

printf("%d\n", c);

-16

This is two's complement sign negation. Processor is doing it when you use '-' operator when you want to negate value or subtrackt it.

Converting float is simpler. Just negate first bit (shoosh gave you example how to do this).

EDIT:

Ok, guys. I give up. Here is my compiler independent version:

#include <stdio.h>

unsigned int adder(unsigned int a, unsigned int b) {
    unsigned int loop = 1;
    unsigned int sum  = 0;
    unsigned int ai, bi, ci;

    while (loop) {
        ai = a & loop;
        bi = b & loop;
        ci = sum & loop;
        sum = sum ^ ai ^ bi;      // add i-th bit of a and b, and add carry bit stored in sum i-th bit
        loop = loop << 1;
        if ((ai&bi)|(ci&ai)|(ci&bi)) sum = sum^loop; // add carry bit
    }

    return sum;
}

unsigned int sub(unsigned int a, unsigned int b) {
    return adder(a, adder(~b, 1));    // add negation + 1 (two's complement here)
}


int main() {
    unsigned int a = 35;
    unsigned int b = 40;

    printf("%u - %u = %d\n", a, b, sub(a, b)); // printf function isn't compiler independent here

    return 0;
}

I'm using unsigned int so that any compiler will treat it the same.

If you want to subtract negative values, then do it that way:

 unsgined int negative15 = adder(~15, 1);

Now we are completly independent of signed values conventions. In my approach result all ints will be stored as two's complement - so you have to be careful with bigger ints (they have to start with 0 bit).

klew
  • 14,837
  • 7
  • 47
  • 59
  • that's assuming the underlying HW implements subtraction like that. That's a good assumption, but in an interview it might be a false assumption. – Nathan Fellman Mar 31 '09 at 08:07
  • I don't know any hardware that doesn't support it. Negation is very simple bit operation (NAND). Adding is some XORs and ANDs (both can be done with NAND) connected together. It's very hard to imagine something simpler. – klew Mar 31 '09 at 08:11
  • 1
    The C99 TC2 standard 6.2.6.2 clause 2 states that there are three possible representations of negation for ints. Only one is two's complement. http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf – Pontus Gagge Mar 31 '09 at 13:57
  • 1
    Read carefully, there is said about two possible representations: two's and one's complement. The only difference is in interpretating result bits. If you'd interpretate my result as one's complement, you'd get wrong result. But the interpretation is done on printing result, not during bin operation – klew Mar 31 '09 at 14:34
  • Interesting approach... I must confess I'm completely stumped as to how printf() 'knows' to compensate for the nonstandard result if your compiler uses one's complement or even sign-and-magnitude instead... or have you left something out? – Pontus Gagge Mar 31 '09 at 15:36
  • I'm sorry, you are right, there are three representation, I misread it. – klew Mar 31 '09 at 16:38
  • As you note, printf() still isn't guaranteed to print out the right answer, and sub(a,b)+b isn't necessarily a on all architectures. But at least you're getting the bit pattern for the two's complement answer... ugh, tough going! – Pontus Gagge Apr 01 '09 at 17:30
  • If you wish I can also write printing function for two's complement. It is quite easy. And, as my answer gives functions adder and sub, you are not allowed do add something using + :). – klew Apr 01 '09 at 21:09
13

Pontus is right, 2's complement is not mandated by the C standard (even if it is the de facto hardware standard). +1 for Phil's creative answers; here's another approach to getting -1 without using the standard library or the -- operator.

C mandates three possible representations, so you can sniff which is in operation and get a different -1 for each:

negation= ~1;
if (negation+1==0)                 /* one's complement arithmetic */
    minusone= ~1;
else if (negation+2==0)            /* two's complement arithmetic */
    minusone= ~0;
else                               /* sign-and-magnitude arithmetic */
    minusone= ~0x7FFFFFFE;

r= a+b*minusone;

The value 0x7FFFFFFFE would depend on the width (number of ‘value bits’) of the type of integer you were interested in; if unspecified, you have more work to find that out!

bobince
  • 528,062
  • 107
  • 651
  • 834
9
  • + No bit setting
  • + Language independent
  • + Can be adjusted for different number types (int, float, etc)
  • - Almost certainly not your C homework answer (which is likely to be about bits)

Expand a-b:

a-b = a + (-b)
    = a + (-1).b

Manufacture -1:

float:             pi = asin(1.0);
(with    minusone_flt = sin(3.0/2.0*pi);
math.h)           or  = cos(pi)
                  or  = log10(0.1)
complex: minusone_cpx = (0,1)**2; // i squared
integer: minusone_int = 0; minusone_int--; // or convert one of the floats above
Phil H
  • 19,928
  • 7
  • 68
  • 105
  • @tomlogic: Well, not really. It's not -(-foo), but a call to the -- decrement operator for the integer variable `minusone_int`. You can probably call it directly if you know an alias for it. – Phil H Jun 10 '10 at 16:03
  • All of your floating point examples depend on implementation-specific precision. Some of them are likely not to work due to rounding errors; the only one I'd remotely trust is `asin(1.0)` since it involves only exact arguments. – R.. GitHub STOP HELPING ICE Aug 13 '10 at 18:51
  • The cos(2pi) is 1, I think you were thinking of the cos(pi) – micmoo Aug 13 '10 at 19:15
  • The integer one uses `-`. – S.S. Anne Apr 01 '20 at 21:23
6

  • + No bit setting
  • + Language independent
  • + Independent of number type (int, float, etc)
  • - Requires a>b (ie positive result)
  • - Almost certainly not your C homework answer (which is likely to be about bits)
  • a - b = c

    restricting ourselves to the number space 0 <= c < (a+b):

           (a - b) mod(a+b) = c mod(a+b)
    a mod(a+b) - b mod(a+b) = c mod(a+b)
    

    simplifying the second term:

    (-b).mod(a+b) = (a+b-b).mod(a+b)
                  = a.mod(a+b)
    

    substituting:

    a.mod(a+b) + a.mod(a+b) = c.mod(a+b)
    2a.mod(a+b) = c.mod(a+b)
    

    if b>a, then b-a>0, so:

    c.mod(a+b) = c
    c = 2a.mod(a+b)
    

    So, if a is always greater than b, then this would work.

    Phil H
    • 19,928
    • 7
    • 68
    • 105
    5

    Given that encoding integers to support two's complement is not mandated in C, iterate until done. If they want you to jump through flaming hoops, no need to be efficient about it!

    int subtract(int a, int b)
    {
      if ( b < 0 )
        return a+abs(b);
      while (b-- > 0)
        --a;
      return a;
    }
    

    Silly question... probably silly interview!

    Pontus Gagge
    • 17,166
    • 1
    • 38
    • 51
    • Actually, that's quite a good interview question. A right answer would show an intimate acquaintance with both the language and the hardware and some out-of-the-box thinking. It only sounds silly because it is phrased as a riddle. – shoosh Mar 31 '09 at 08:05
    • Answer is easy if you had boolean algebra lessons :) – klew Mar 31 '09 at 08:15
    • 3
      By the way, you are using '-' operator but hidden in '--' operator. – klew Mar 31 '09 at 08:18
    • 2
      Nope, two separate operators, by definition. The tokens just happen to be represented by the same ASCII codes! (The unstaed condition in the question is whether just the binary '-' or also the unary '-' is forbidden.) – Pontus Gagge Mar 31 '09 at 08:36
    • 1
      According to your answer, I can write function subtract(int a, int b) {return a-b;} , put it into library and use it in my code. '--' is subtraction: some_value - 1. Hm, maybe it will be simpler using -= operator? :) – klew Mar 31 '09 at 13:08
    • @klew: look at it this way, what would --a get translated to in machine code on an x86? What about a -= b? DEC and SUB, respectively. Are they the same? They might use the same microcode, but definitely have different opcodes. – Pontus Gagge Mar 31 '09 at 13:32
    • @klew: Look at the (edited) question: it asks us not to use either form of the '-' operator. If you can find a standard library function to subtract, that should also be an acceptable answer. – Pontus Gagge Mar 31 '09 at 13:33
    • By the way, if you will decrement below 0, you will get values in two's complement :). One's complement has negative 0 and for sure it isn't used in any add and sub operations. And interpretation of these bit values isn't HW problem, but software. – klew Mar 31 '09 at 14:44
    • @klew: Yep. On *some* architectures, such as x86. And on some it'll be one's complement, and on some it's gonna be sign+magnitude, as far as the C standard is concerned. Or do you claim universal adoption of two's complement (like, e.g., little-endian byte order)? – Pontus Gagge Mar 31 '09 at 19:19
    • Yes, two's complement should rule the world :). Today I asked question if somebody knows any present-day C compiler that gives non two's complement number and I didn't get answer. Maybe you know some? – klew Apr 01 '09 at 21:13
    • '--' implies '-'. I would not accept this in language-lawyer mode. – Michael Foukarakis Jul 06 '10 at 10:01
    • @Michael: that's your privilege. Similarly in e.g. x86 assembler, DEC and SUB probably both involve the same or related microcode for the ALU, yet they are separate opcodes. IMHO, @bobince has the best answer here. Silly questions should get silly answers! – Pontus Gagge Jul 06 '10 at 10:42
    • Agreed, although I think it's a neat and conclusive answer - not silly at all. The concept of interview questions such as this, that's silly. ;-) – Michael Foukarakis Jul 06 '10 at 11:09
    • If -- is allowed, then answer is far from optimal, and you probably wouldn't pass the interview. Using -- better do: a+(0--)*b – Uri London Mar 23 '11 at 06:46
    • Thanks Uri: I'm **sure** efficiency would be uppermost in the interviewers' minds... Silly questions deserve, nay, **require** silly answers. – Pontus Gagge Mar 23 '11 at 08:22
    3

    For subtracting in C two integers you only need:

    int subtract(int a, int b)
    {
        return a + (~b) + 1;
    }
    

    I don't believe that there is a simple an elegant solution for float or double numbers like for integers. So you can transform your float numbers in arrays and apply an algorithm similar with one simulated here

    Ionel Bratianu
    • 836
    • 2
    • 13
    • 26
    • The C99 TC2 standard 6.2.6.2 clause 2 states that there are three possible representations of negation for ints. Only one is two's complement. http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf – Pontus Gagge Mar 31 '09 at 13:59
    • Therefore, this answer will work on most implementations, but really uses undefined behavious which may bomb in the future. – Pontus Gagge Mar 31 '09 at 13:59
    2

    If you want to do it for floats, start from a positive number and change its sign bit like so:

    float f = 3;
    *(int*)&f |= 0x80000000;
    // now f is -3.
    float m = 4 + f; 
    // m = 1
    

    You can also do this for doubles using the appropriate 64 bit integer. in visual studio this is __int64 for instance.

    shoosh
    • 76,898
    • 55
    • 205
    • 325
    • Repeat after me: "undefined behaviour". This interview question seems to sort out those who get things done, from those who do things that (are guaranteed to) work! – Pontus Gagge Mar 31 '09 at 09:05
    • Show me a modern processor which has floating point numbers which are not IEEE-754. This question sorts the sane from the anal retentive. – shoosh Mar 31 '09 at 12:46
    • @shoosh. Perhaps. Or those who have been bitten by their assumptions from those who have yet to be. Depends on who the interviewers are looking for. (Mind you, hacking with undefined behaviour is right and proper at times: I just think those times are the exception.) – Pontus Gagge Mar 31 '09 at 14:46
    • @klew/shoosh: Hmmm... rechecking, it might actually be safer, standard-wise, than bit-twiddling ints. Still not sure about byte order issues, but IEEE-754 provides abstraction from hardware dependencies. My apologies. Interesting discussion, though. – Pontus Gagge Mar 31 '09 at 14:55
    • @Pontus: with ints it's the same. This will work even on processor that has only add and bit operations. Two's complement is only the way that program interpretate bits. And it will work as long as we will use boolean algebra. [...] – klew Mar 31 '09 at 15:09
    • [...] Even if your compiler will force you to use one's complement you still can write your own function to print it correctly as two's complement – klew Mar 31 '09 at 15:10
    • @klew: Minor nitpick: discrete maths, yes, but only peripherally boolean algebra per se... As for ints, that discussion belongs to the other answer (with the magic printf() function!). – Pontus Gagge Mar 31 '09 at 15:39
    1

    I suppose this

    b - a = ~( a + ~b)

    jonny
    • 1,326
    • 9
    • 44
    • 62
    • The C99 TC2 standard 6.2.6.2 clause 2 states that there are three possible representations of negation for ints. Only one is two's complement. http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf – Pontus Gagge Mar 31 '09 at 13:57
    1

    Assembly (accumulator) style:

    int result = a;
    result -= b;
    
    starblue
    • 55,348
    • 14
    • 97
    • 151
    0

    Not tested. Without using 2's complement:

    #include <stdlib.h>
    #include <stdio.h>
    int sillyNegate(int x) {
       if (x <= 0)
         return abs(x);
       else {
         // setlocale(LC_ALL, "C"); // if necessary.
         char buffer[256];
         snprintf(buffer, 255, "%c%d", 0x2d, x);
         sscanf(buffer, "%d", &x);
         return x;
       }
    }
    

    Assuming the length of an int is much less than 255, and the snprintf/sscanf round-trip won't produce any unspecified behavior (right? right?).

    The subtraction can be computed using a - b == a + (-b).


    Alternative:

    #include <math.h>
    int moreSillyNegate(int x) {
       return x * ilogb(0.5);  // ilogb(0.5) == -1;
    }
    

    kennytm
    • 510,854
    • 105
    • 1,084
    • 1,005
    0

    This would work using integer overflow:

    #include<limits.h>    
    int subtractWithoutMinusSign(int a, int b){
             return a + (b * (INT_MAX + INT_MAX + 1));
    }
    

    This also works for floats (assuming you make a float version…)

    micmoo
    • 5,991
    • 3
    • 22
    • 16
    0

    For the maximum range of any data type , one's complement provide the negative value decreased by 1 to any corresponding value. ex:
    ~1 --------> -2
    ~2---------> -3
    and so on... I will show you this observation using little code snippet

    #include<stdio.h>
    int main()
    {
       int a , b;
       a=10;
       b=~a; // b-----> -11    
       printf("%d\n",a+~b+1);// equivalent to a-b
       return 0;
    }
    

    Output: 0
    Note : This is valid only for the range of data type. means for int data type this rule will be applicable only for the value of range[-2,147,483,648 to 2,147,483,647]. Thankyou .....May this help you

    Minion
    • 964
    • 14
    • 16
    0

    Iff:

    1. The Minuend is greater or equal to 0, or
    2. The Subtrahend is greater or equal to 0, or
    3. The Subtrahend and the Minuend are less than 0

    multiply the Minuend by -1 and add the result to the Subtrahend:

    SUB + (MIN * -1)
    

    Else multiply the Minuend by 1 and add the result to the Subtrahend.

    SUB + (MIN * 1)
    

    Example (Try it online):

    #include <stdio.h>
    
    int subtract (int a, int b)
    {
        if ( a >= 0 || b >= 0 || ( a < 0 && b < 0 ) )
        {
            return a + (b * -1);
        }
    
        return a + (b * 1); 
    }
    
    int main (void)
    {
        int x = -1;
        int y = -5;
        printf("%d - %d = %d", x, y, subtract(x, y) );
    }
    

    Output:

    -1 - -5 = 4
    
    0

    As the question asked for integers not ints, you could implement a small interpreter than uses Church numerals.

    Pete Kirkham
    • 48,893
    • 5
    • 92
    • 171
    0

    Create a lookup table for every possible case of int-int!

    Jotux
    • 147
    • 1
    • 9
    -1
            int num1, num2, count = 0;
            Console.WriteLine("Enter two numebrs");
            num1 = int.Parse(Console.ReadLine());
            num2 = int.Parse(Console.ReadLine());
            if (num1 < num2)
            {
                num1 = num1 + num2;
                num2 = num1 - num2;
                num1 = num1 - num2;
            }
            for (; num2 < num1; num2++)
            {
                count++;
            }
            Console.WriteLine("The diferrence is " + count);
    
    Clifford
    • 88,407
    • 13
    • 85
    • 165
    • 1
      Given the question and its tags, I do not believe that C++/CLI and use of .Net classes is a valid solution, although I accept that you used this only for I/O - an unnecessary elaboration perhaps? Also this solution has *two* instances of the `-` operator, so is hardly a solution at all! – Clifford Jun 09 '10 at 10:15
    -1
    void main()
    {
    int a=5;
    int b=7;
    
    while(b--)a--;
    printf("sud=%d",a);
    
    }
    
    thkala
    • 84,049
    • 23
    • 157
    • 201
    neelam
    • 1