2
\$\begingroup\$

This is a follow-up question for A recursive_count Function For Various Type Arbitrary Nested Iterable Implementation in C++ and A Summation Function For Boost.MultiArray in C++. I am trying to implement an arithmetic_mean template function for calculating the arithmetic mean value of various type arbitrary nested iterable things. The recursive_reduce function (thanks to G. Sliepen's answer) and the recursive_size function are used here. Because both recursive_reduce function and recursive_size function are needed in the arithmetic_mean function here, there are two new concepts is_recursive_reduceable and is_recursive_sizeable created as follows.

template<typename T>
concept is_recursive_reduceable = requires(T x)
{
    recursive_reduce(x, 0.0);
};

template<typename T>
concept is_recursive_sizeable = requires(T x)
{
    recursive_size(x);
};

Next, the main part of arithmetic_mean template function:

template<class T> requires (is_recursive_reduceable<T> && is_recursive_sizeable<T>)
auto arithmetic_mean(const T& input)
{
    return (recursive_reduce(input, 0.0)) / (recursive_size(input));
}

Some test cases of this arithmetic_mean template function.

//  std::vector<int> case
std::vector<int> test_vector = {
    1, 2, 3
};
auto arithmetic_mean_result1 = arithmetic_mean(test_vector);
std::cout << arithmetic_mean_result1 << std::endl;

//  std::vector<std::vector<int>> case
std::vector<decltype(test_vector)> test_vector2 = {
    test_vector, test_vector, test_vector
};
auto arithmetic_mean_result2 = arithmetic_mean(test_vector2);
std::cout << arithmetic_mean_result2 << std::endl;

// std::deque<int> case
std::deque<int> test_deque;
test_deque.push_back(1);
test_deque.push_back(1);
test_deque.push_back(1);
auto arithmetic_mean_result3 = arithmetic_mean(test_deque);
std::cout << arithmetic_mean_result3 << std::endl;

// std::deque<std::deque<int>> case
std::deque<decltype(test_deque)> test_deque2;
test_deque2.push_back(test_deque);
test_deque2.push_back(test_deque);
test_deque2.push_back(test_deque);
auto arithmetic_mean_result4 = arithmetic_mean(test_deque2);
std::cout << arithmetic_mean_result4 << std::endl;

A Godbolt link is here.

All suggestions are welcome.

The summary information:

\$\endgroup\$
1
  • \$\begingroup\$ Arithmetic mean, even of two integers, has more pitfalls than you might expect! \$\endgroup\$ Commented Nov 27, 2020 at 13:44

1 Answer 1

1
\$\begingroup\$

Instead of simply printing output, it would be better to have self-checking unit tests, so you can fail your build as soon as you break something, rather than having to notice a change in the output.

You probably want to include some tests with very large (positive and negative) values to make sure you get accurate results with these, and don't fall foul of integer overflow (which will cause gross inaccuracy with unsigned types, and is Undefined Behaviour with signed integer types).

It's disappointing that there are no tests using primitive types other than int.

\$\endgroup\$
0

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.