How can I safely average two unsigned ints in C++?

后端 未结 10 887
情书的邮戳
情书的邮戳 2020-12-07 19:05

Using integer math alone, I\'d like to \"safely\" average two unsigned ints in C++.

What I mean by \"safely\" is avoiding overflows (and anything else that can be th

相关标签:
10条回答
  • 2020-12-07 19:25

    What you have is fine, with the minor detail that it will claim that the average of 3 and 3 is 2. I'm guessing that you don't want that; fortunately, there's an easy fix:

    unsigned int average = a/2 + b/2 + (a & b & 1);
    

    This just bumps the average back up in the case that both divisions were truncated.

    0 讨论(0)
  • 2020-12-07 19:29

    In C++20, you can use std::midpoint:

    template <class T>
    constexpr T midpoint(T a, T b) noexcept;
    

    The paper P0811R3 that introduced std::midpoint recommended this snippet (slightly adopted to work with C++11):

    #include <type_traits>
    
    template <typename Integer>
    constexpr Integer midpoint(Integer a, Integer b) noexcept {
      using U = std::make_unsigned<Integer>::type;
      return a>b ? a-(U(a)-b)/2 : a+(U(b)-a)/2;
    }
    

    For completeness, here is the unmodified C++20 implementation from the paper:

    constexpr Integer midpoint(Integer a, Integer b) noexcept {
      using U = make_unsigned_t<Integer>;
      return a>b ? a-(U(a)-b)/2 : a+(U(b)-a)/2;
    }
    
    0 讨论(0)
  • 2020-12-07 19:35

    And the correct answer is...

    (A&B)+((A^B)>>1)
    
    0 讨论(0)
  • 2020-12-07 19:38

    Your method is not correct if both numbers are odd eg 5 and 7, average is 6 but your method #3 returns 5.

    Try this:

    average = (a>>1) + (b>>1) + (a & b & 1)
    

    with math operators only:

    average = a/2 + b/2 + (a%2) * (b%2)
    
    0 讨论(0)
提交回复
热议问题