signed = unsigned - unsigned

Go To Last Post
7 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

say I have 2 unsigned ints, var1 and var2, both are larger than can fit in a signed int. Now I have a signed int result.
so lets say;

unsigned int var1 = 45678;
unsigned int var2 = 56789;
signed int result;

and I do

result=var1-var2;

var1-var2 will be small enough to fit in the signed int but I don't know if the calculation will work as written. Will it?

Edward

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes, it should, although you might need a typecast.

In the C language, whenever a calculation is performed it is implicitly done in the size of the largest datatype (in this case unsigned ints). The result is also in the form of the largest datatype, but may be cast as neccesary.

Some cavets; bitwise operations cause the implicit promotion of a char to an int, and all constants are by default ints unless specified.

In your case the calculation will be performed as unsigned ints, then typecast to a signed int.

However, as a signed int and an unsigned int occupies the same amount of bits, what's the point? You'll never get a valid negative value as the calculation in unsigned before it is typecasted.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That was my issue, and I can't cast the inputs as signed ints as they are too large. I'm guessing my only option is to cast them to signed longs then cast the result back down to a signed int, which is somewhat of a pain.

Edward

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I tried this out and was surprised by the results. First I expected a warning from the compiler that the result may be too large for an integer and secondly, when appropriate, I did get a negative result. This was with WinAVR.

unsigned int i=54000;
unsigned int j=49000;

int n = i-j;

char buffer[128];
sprintf(buffer, "%u - %u = %d", i, j, n);
SendLine(buffer);

n = j-i;
sprintf(buffer, "%u - %u = %d", i, j, n);
SendLine(buffer);

Quote:
The output was
54000 - 49000 = 5000
54000 - 49000 = -5000

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That's really weird.... do you have the relevant asm? NM, why don't I just do it myself ;'] ? I guess the compiler might be smart and checking the underflow bit, or doing a promotion to 32bits for us, or I think more likely we are just lucky that an underflow by x in an unsigned int has the same bit representation as -x in a signed int.

Edward

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yup, we're just lucky. So it works....

Edward

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

No luck here - just basic maths.

The compiler doesn't know if the result is going to generate an underflow at run time - so don't expect it to use 32bits. You've told it to use ints so the result will be a 16 bit value. How you interpret that result is up to you.

Using a calculator - this is what happens:
49000-54000 = -5000 (this we know)
convert to this hex:
0xFFFFFFEC78

because the result must fit in 16 bits, we knock of the extra bits:
0xEC78
as an unsigned value this is 60536decimal
or -5000 as a signed value.

Binary arithmetic my friends. Just goesto show you must be careful choosing your variable sizes, otherwise weird stuff will happen.