8
\$\begingroup\$

Because std doesn't provide an overloaded version of std::abs for std::size_t, I built a version to calculate distance between unsigned numbers.

It subtracts the smaller one from the larger one, to prevent a negative result, since in unsigned integer it would wrap around.

std::size_t size_type_abs(std::size_t a, std::size_t b)
{
    return std::max(a, b) - std::min(a, b);
}

Is this implementation correct and efficient?

\$\endgroup\$

2 Answers 2

9
\$\begingroup\$

This function computes absolute difference, not absolute value, so it shouldn't be called abs. absolute_difference? size_diff?

What will you use this function for? Are you using size_t for something other than sizes, so an absolute difference is meaningful?

std::max(a, b) - std::min(a, b) is harder to read than a simple conditional:

return a > b ? a - b : b - a;

This function isn't specific to size_t; it can be defined for any type that supports comparison and subtraction:

template<typename T>
T abs_diff(T a, T b) {
  return a > b ? a - b : b - a;
}

If you do want to define it only for size_t, using std::size_t would save some repetitions of std::.

\$\endgroup\$
4
  • 1
    \$\begingroup\$ "std::max(a, b) - std::min(a, b) is harder to read than a simple conditional" seems false to me. For example its much easier to see the difference between std::max(a, b) - std::min(a, b) and std::min(a, b) - std::max(a, b) than between a > b ? a - b : b - a and a > b ? b - a : a - b, or b > a ? a - b : b - a, or b > a ? b - a : a - b. \$\endgroup\$
    – bames53
    Jul 16, 2017 at 3:44
  • \$\begingroup\$ There exists a proposal for abs_diff, unfortunately it doesn't seem to have had follow up open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4318.pdf - meetingcpp.com/blog/items/… \$\endgroup\$
    – Antonio
    May 16, 2022 at 15:53
  • \$\begingroup\$ Your function could be improved by adding const to the input parameters as they are not going to be modified. \$\endgroup\$ Jan 2 at 16:35
  • \$\begingroup\$ using std::size_t; would need to be in the containing scope (namespace, or even translation-unit) to shorten the code, and the consequences of that are probably not worth the small benefit. \$\endgroup\$ Jan 3 at 16:41
7
\$\begingroup\$

This probably isn't the most efficient method possible. In particular std::min and std::max are typically implemented something like:

template <class T>
T std::min(T a, T b) { return a < b ? a : b; }

template <class T>
T std::max(T a, T b) { return a < b ? b : a; }

So, the overall code looks something like this:

std::size_t size_type_abs(std::size_t a, std::size_t b) { 
    return a < b ? a : b - a < b ? b : a;
}

The compiler may (but certainly won't necessarily) recognize that one of these comparisons is redundant. I'd prefer to ensure that only one comparison is done:

std::size_t size_type_abs(std::size_t a, std::size_t b) { 
   return a < b ? b - a : a - b;
}

This might be about the same efficiency as your version, or it might be marginally better. I'd be rather surprised to see it any less efficient though. I see little difference in readability between the two, so no real preference on that account.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.