I recently learned that integer overflow is an undefined behavior in C (side question - is it also UB in C++?)
Often in C programming you need to find the average of two
The simplest (and usually fastest) way to average two int
over the entire range [INT_MIN...INT_MAX]
is to resort to a wider integer type. (Suggested by @user3100381.) Let us call that int2x.
int average_int(int a, int b) {
return ((int2x) a + b)/2;
}
Of course this obliges a wider type to exist - so let's look at a solution that does not require a wider type.
Challenges:
Q: When one int
is odd and the other is even, which way should rounding occur?
A: Follow average_int()
above and round toward 0. (truncate).
Q: Can code use %
?
A: With pre-C99 code, the result of a % 2
allows for different results when a < 0
. So let us not use %
.
Q: Does int
need to have about symmetric range of positive and negative numbers?
A: Since C99 the number of negative numbers is the the same (or 1 more) than the number of positive numbers. Let us try not to require this.
SOLUTION:
Perform tests to determine is if overflow may occur. If not, simple use (a + b) / 2
. Otherwise, add half the difference (signed same as answer) to the smaller value.
The following gives the same answer as average_int()
without resorting to a wider integer type. It protects against int overflow and does not require INT_MIN + INT_MAX
to be 0 or -1. It does not depends on encoding to be 2's complement, 1's complement or sign-magnitude.
int avgC2(int a, int b) {
if (a >= 0) {
if (b > (INT_MAX - a)) {
// (a+b) > INT_MAX
if (a >= b) {
return (a - b) / 2 + b;
} else {
return (b - a) / 2 + a;
}
}
} else {
if (b < (INT_MIN - a)) {
// (a+b) < INT_MIN
if (a <= b) {
return (a - b) / 2 + b;
} else {
return (b - a) / 2 + a;
}
}
}
return (a + b) / 2;
}
At most, 3 if()
s occur with any pair of int
.