What is the right way to find the average of two values?

后端 未结 8 1192
北荒
北荒 2021-02-19 00:58

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

8条回答
  •  春和景丽
    2021-02-19 01:13

    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.

提交回复
热议问题