views:

1414

answers:

17

How can i do subtraction of integers in C without using either the unary or binary '-' operator?

Or can we do the same for other data types like float/double?

+13  A: 

have a look at the two's complement

tanascius
The C standard does not mandate two's complement integer encoding.
sigjuice
@sigjuice: are you sure? There's nothing special in two's complement and it's the simplest way to support negative integers.
klew
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
This interview question could differentiate between those who get the job done quickly, and those who get it done safely. The interviewer may be looking for either...
Pontus Gagge
Since the assignment has no purpose other that as a test of someone's deeper understanding of binary integer arithmetic I doubt that the possibility of undefined behaviour is an issue. In fact if you presented this solution, but then mentioned the (not unreasonable) assumption of 2's complement, I'd give additional credit (or it would be my next question).
Clifford
*"The C standard does not mandate two's complement integer encoding."* But when was the last time that you used a machine that didn't use two's complement? (Last time I used one was in 1979!)
Stephen C
Technically you always have twos complement if you want. Simply don't use any signed types and interpret the unsigned types as twos-complement signed types yourself. The only things that aren't entirely trivial are inequality comparisons and division.
R..
+6  A: 

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
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
Answer is easy if you had boolean algebra lessons :)
klew
By the way, you are using '-' operator but hidden in '--' operator.
klew
<LanguageLawyer>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.) </LanguageLawyer>
Pontus Gagge
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
@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
@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
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
@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
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
'--' implies '-'. I would not accept this in language-lawyer mode.
Michael Foukarakis
@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
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
+4  A: 

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
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
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
This is good answer and it won't give you undefined behaviour.
klew
@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
@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
@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
[...] 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
@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
+13  A: 
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
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
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
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
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
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
I'm sorry, you are right, there are three representation, I misread it.
klew
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
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
A: 

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
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
Therefore, this answer will work on most implementations, but really uses undefined behavious which may bomb in the future.
Pontus Gagge
+1  A: 

I suppose this

b - a = ~( a + ~b)

jonny
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
+2  A: 

Take a look here: Add/Subtract using bitwise operators

Naveen
A: 

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

Pete Kirkham
+1  A: 

Assembly (accumulator) style:

int result = a;
result -= b;
starblue
You're still using a binary '-' operator.
Liudvikas Bukys
No. -= is a different operator.
recursive
+3  A: 

  • + 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 
           (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
    But you assume "b>a" to get to the last step! Surely you mean "If a>b then a-b>0".
    Pontus Gagge
    It seeems edits and votes have been lost. Creative answer!
    Pontus Gagge
    You should see my other answer! Even better, and even less limited!
    Phil H
    @Phil H: Yeah, but this answer is so much more elegant (and brain-hurtful -- at first)!
    Pontus Gagge
    Modulos are indeed a great pain between the ears!
    Phil H
    Oh, just take a look at polynomial modulos over fields -- that's pure fun (once your brain has finished resetting itself).
    Pontus Gagge
    +5  A: 
    • + 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(2.0*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
    +1 Brilliant for manufacturing -1 :)
    pjc50
    +1 I knew I learnt about i for some reason!
    MPritch
    But your calculation of minusone_int uses a unary negate...
    tomlogic
    @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
    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..
    The cos(2pi) is 1, I think you were thinking of the cos(pi)
    micmoo
    +9  A: 

    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
    Nice solution. Regarding your last comment on sign-and-magnitude, I think you could do the following for any number of bits in the unsigned `minusone`: `minusone = ((~1 << 1) >> 1);`
    tomlogic
    `~1<<1` results in undefined behavior (signed integer overflow) and the subsequent `>>1` has implementation-defined behavior.
    R..
    Try: `#define minusone (~1+1==0 ? ~1 : ~1+2==0 ? ~0 : ~(INT_MAX/2*2))`
    R..
    A: 

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

    Jotux
    Apart from "normal" votes, each question should have LOL-vote count;)
    el.pescado
    A: 
            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);
    
    Rahul Vats
    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
    A: 

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

    void main() { int a=5; int b=7;

    while(b--)a--; printf("sud=%d",a);

    }

    neelam
    A: 

    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
    This has undefined behavior. However, this would work nicely: `return a + b * (INT_MIN + INT_MAX);` ;-)
    R..