mirror of
https://github.com/boostorg/math.git
synced 2026-01-19 04:22:09 +00:00
Vectorize mean calculation.
This commit is contained in:
@@ -30,12 +30,47 @@ auto mean(ForwardIterator first, ForwardIterator last)
|
||||
}
|
||||
return mu;
|
||||
}
|
||||
else if constexpr (std::is_same_v<typename std::iterator_traits<ForwardIterator>::iterator_category, std::random_access_iterator_tag>)
|
||||
{
|
||||
size_t elements = std::distance(first, last);
|
||||
Real mu0 = 0;
|
||||
Real mu1 = 0;
|
||||
Real mu2 = 0;
|
||||
Real mu3 = 0;
|
||||
Real i = 1;
|
||||
auto end = last - (elements % 4);
|
||||
for(auto it = first; it != end; it += 4) {
|
||||
Real inv = Real(1)/i;
|
||||
Real tmp0 = (*it - mu0);
|
||||
Real tmp1 = (*(it+1) - mu1);
|
||||
Real tmp2 = (*(it+2) - mu2);
|
||||
Real tmp3 = (*(it+3) - mu3);
|
||||
// please generate a vectorized fma here
|
||||
mu0 += tmp0*inv;
|
||||
mu1 += tmp1*inv;
|
||||
mu2 += tmp2*inv;
|
||||
mu3 += tmp3*inv;
|
||||
i += 1;
|
||||
}
|
||||
Real num1 = Real(elements - (elements %4))/Real(4);
|
||||
Real num2 = num1 + Real(elements % 4);
|
||||
|
||||
for (auto it = end; it != last; ++it)
|
||||
{
|
||||
mu3 += (*it-mu3)/i;
|
||||
i += 1;
|
||||
}
|
||||
|
||||
return (num1*(mu0+mu1+mu2) + num2*mu3)/Real(elements);
|
||||
}
|
||||
else
|
||||
{
|
||||
Real mu = 0;
|
||||
Real i = 1;
|
||||
for(auto it = first; it != last; ++it) {
|
||||
mu = mu + (*it - mu)/i;
|
||||
auto it = first;
|
||||
Real mu = *it;
|
||||
Real i = 2;
|
||||
while(++it != last)
|
||||
{
|
||||
mu += (*it - mu)/i;
|
||||
i += 1;
|
||||
}
|
||||
return mu;
|
||||
|
||||
@@ -124,6 +124,17 @@ void test_integer_mean()
|
||||
BOOST_TEST(abs(m1 - m2) < tol*abs(m1));
|
||||
}
|
||||
|
||||
template<class RandomAccessContainer>
|
||||
auto naive_mean(RandomAccessContainer const & v)
|
||||
{
|
||||
typename RandomAccessContainer::value_type sum = 0;
|
||||
for (auto & x : v)
|
||||
{
|
||||
sum += x;
|
||||
}
|
||||
return sum/v.size();
|
||||
}
|
||||
|
||||
template<class Real>
|
||||
void test_mean()
|
||||
{
|
||||
@@ -172,6 +183,23 @@ void test_mean()
|
||||
}
|
||||
Real m2 = boost::math::tools::mean(v);
|
||||
BOOST_TEST(abs(m1 - m2) < tol*abs(m1));
|
||||
|
||||
// Stress test:
|
||||
for (size_t i = 1; i < 30; ++i)
|
||||
{
|
||||
v = generate_random_vector<Real>(i, 12803);
|
||||
auto naive_ = naive_mean(v);
|
||||
auto higham_ = boost::math::tools::mean(v);
|
||||
if (abs(higham_ - naive_) >= 100*tol*abs(naive_))
|
||||
{
|
||||
std::cout << std::hexfloat;
|
||||
std::cout << "Terms = " << v.size() << "\n";
|
||||
std::cout << "higham = " << higham_ << "\n";
|
||||
std::cout << "naive_ = " << naive_ << "\n";
|
||||
}
|
||||
BOOST_TEST(abs(higham_ - naive_) < 100*tol*abs(naive_));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<class Complex>
|
||||
|
||||
Reference in New Issue
Block a user