Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Explanation of the safe average of two numbers

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).

like image 272
gsingh2011 Avatar asked Oct 01 '13 01:10

gsingh2011


People also ask

How do you calculate the average of 2 numbers?

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.

What does the average of two numbers mean?

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.

How do you find the average of two numbers in C++?

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.


2 Answers

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);
like image 136
Joni Avatar answered Oct 16 '22 14:10

Joni


The C++ version has a hidden cheat: low and high are ints 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.

like image 43
Adam Avatar answered Oct 16 '22 15:10

Adam