6

I want alwaysPositive to be assigned a positive number with all possible values for lareValue1 and largeValue2 (these are at least 1).

The following statement causes a buffer overflow:

int alwaysPositive = (largeValue1 + largeValue2) / 2;

I know I can prevent it by substracting and adding:

int alwaysPositive = largeValue1 + ((largeValue2 - largeValue1) / 2);

But in other programming languages I can use an unsigned bitshift to do the trick:

int alwaysPositive3 = (largeValue1 + largeValue2) >>> 1;

How can I do this in C#?


The answers below all solve the problem. There are probably lots of ways to do this, but they all (including my solutions) have one thing in common: they all look obfuscated.

Kevin Fairchild
  • 10,891
  • 6
  • 33
  • 52
Paco
  • 8,335
  • 3
  • 30
  • 41
  • Forgive my ignorance, but why would you want to do this though? – Martin Clarke Sep 22 '08 at 20:53
  • The reason I tried to do this is reinventing the wheel: implementing a binary search. Why would I write my own version? I don't know... – Paco Sep 22 '08 at 21:43
  • Just FYI, your code samples do different things. I think you want parentheses in the first one. PS. Were you inspired by http://googleresearch.blogspot.com/2006/06/extra-extra-read-all-about-it-nearly.html ? – A. Rex Sep 23 '08 at 01:14
  • I was actually inspired by the book "datastructures and algorithms" that was doing it wrong in java. – Paco Sep 23 '08 at 09:27

6 Answers6

3
int alwaysPositive = (largeValue1 >> 1) + (largeValue2 >> 1) + (largeValue1 & largeValue2 & 0x01);

The idea behind the above is that if you pre-divide the results before you add them, then you will avoid the overflow as both high-order bits will be unset. You then add some slight correction logic to increase the value by one if both were positive (round down). If you only care if either one was positive (round off) then you could change it to

int alwaysPositive = (largeValue1 >> 1) + (largeValue2 >> 1) + ((largeValue1 | largeValue2) & 0x01);
Orion Adrian
  • 19,053
  • 13
  • 51
  • 67
3

unchecked((largeValue1 + largeValue2) >> 1) is another option.

See the documentation for the unchecked keyword.

Doug McClean
  • 14,265
  • 6
  • 48
  • 70
  • I don't believe this works. All it does is remove the checking that flags that you have a problem. It doesn't actually remove the problem. – Orion Adrian Sep 23 '08 at 01:09
  • I doubt there are many things that only work for unsigned integers. CPUs generally treat signed values the same as signed. – Nefzen Jun 29 '09 at 14:16
2

You can do it this way:

  x = largeValue1;
  y = largeValue2; 
  return (x&y)+((x^y)/2);

That's a bit-twiddling way to get the average of two integers without overflow.

If you want you can replace the division by two with a bit-shift, but the compiler will do that for you anyways.

Nils Pipenbrinck
  • 83,631
  • 31
  • 151
  • 221
0

You could use uints:

uint alwaysPositive = (uint)(largeValue1 + largeValue2) / 2;
Khoth
  • 13,068
  • 3
  • 28
  • 27
0

Not to nitpick, but you mean "integer overflow" rather than "buffer overflow".

I don't know C#, so there may be another way, but you could mimic an unsigned shift by just masking off the top bit: (x >> 1) & 0x80000000

Zebra North
  • 11,412
  • 7
  • 37
  • 49
0
try
{
    checked { alwaysPositive3 = (largeValue1 + largeValue2); }
}
catch (OverflowException ex)
{
   // Corrective logic
}
ilitirit
  • 16,016
  • 18
  • 72
  • 111