Whenever I need to average two numbers for an algorithm like binary search, I always do something like this:
int mid = low + ((high - low) / 2);
I recently saw another way to do it in this post, but I don't understand it. It says you can do this in Java:
int mid = (low + high) >>> 1;
or this in C++:
int mid = ((unsigned int)low + (unsigned int)high)) >> 1;
The C++ version essentially makes both operands unsigned, so doing a shift results in an arithmetic shift instead of a signed shift. I understand what both these pieces of code are doing, but how does this solve the overflow issue? I thought the whole issue was that the intermediate value high + low
could overflow?
Edit:
Oh, duh. All the answers didn't exactly answer my question, but it was @John Zeringue's answer that made it click. I'll try to explain here.
The issue with (high + low)/2
in Java isn't exactly that high + low
overflows (it does overflow since the integers are both signed, but all the bits are still there, and no information is lost). The issue with taking the average like this is the division. The division is operating on a signed value, so your result will be negative. Using the shift instead will divide by two but consider the bits instead of the sign (effectively treating it as unsigned).
Average This is the arithmetic mean, and is calculated by adding a group of numbers and then dividing by the count of those numbers. For example, the average of 2, 3, 3, 5, 7, and 10 is 30 divided by 6, which is 5.
Definition. Average is a number that represents a group of numbers. It is calculated by adding up all the numbers, then dividing the total by the count of numbers. In other words, it is the sum divided by the count. Average of two numbers is given by the sum of the two numbers divided by two.
Now, you have to take three integer type variables name 'x', 'y' and 'sum'. Then you have to take another floating type variable name 'average'. Now using the cout statement prints the message "Enter 2 integers : " Next the cin statement takes the 2 values from the user and put them in x and y respectively.
The code you saw is broken: it doesn't compute the average of negative numbers correctly. If you are operating on non-negative values only, like indexes, that's OK, but it's not a general replacement. The code you have originally,
int mid = low + ((high - low) / 2);
isn't safe from overflow either because the difference high - low
may overflow the range for signed integers. Again, if you only work with non-negative integers it's fine.
Using the fact that A+B = 2*(A&B) + A^B
we can compute the average of two integers without overflow like this:
int mid = (high&low) + (high^low)/2;
You can compute the division by 2 using a bit shift, but keep in mind the two are not the same: the division rounds towards 0 while the bit shift always rounds down.
int mid = (high&low) + ((high^low)>>1);
The C++ version has a hidden cheat: low
and high
are int
s but they're never negative. When you cast them to unsigned int
your sign bit becomes an extra precision bit, which a single addition cannot overflow.
It's not a very good cheat because array indices should be unsigned
anyway.
Like was said elsewhere, i >> 1
means /2
for unsigned integers.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With