Skip to content

Commit f32e689

Browse files
committed
draft for SIMD-aware implementation of variance
1 parent 676f5f8 commit f32e689

File tree

1 file changed

+88
-0
lines changed

1 file changed

+88
-0
lines changed

gallery/simd-variance.cpp

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// [[Rcpp::depends(RcppParallel)]]
2+
#include <RcppParallel.h>
3+
using namespace RcppParallel;
4+
5+
#include <Rcpp.h>
6+
using namespace Rcpp;
7+
8+
/**
9+
* Let's use `Boost.SIMD` to compute the variance for a vector of numbers.
10+
* In contrast to the gallery article [implementing the sum](<TODO!!>),
11+
* we'll take advantage of some of the lower-level facilities provided
12+
* for interacting with packs of values.
13+
*
14+
* The imple
15+
*/
16+
17+
class simd_ssq
18+
{
19+
public:
20+
explicit simd_ssq(double avg) : avg_(avg) {}
21+
22+
template <typename T>
23+
T operator()(const T& t) {
24+
return boost::simd::sqr(t - avg_);
25+
}
26+
27+
private:
28+
double avg_;
29+
};
30+
31+
struct simd_plus
32+
{
33+
template <typename T>
34+
T operator()(const T& lhs, const T& rhs) {
35+
return lhs + rhs;
36+
}
37+
};
38+
39+
// [[Rcpp::export]]
40+
double simdVar(NumericVector data) {
41+
42+
// Bring in the Boost.SIMD components we need
43+
using boost::simd::pack;
44+
using boost::simd::load;
45+
typedef pack<double> packed_type;
46+
47+
// Compute the mean of our dataset
48+
std::size_t n = data.size();
49+
double total = boost::simd::accumulate(data.begin(), data.end(), 0.0, simd_plus());
50+
double avg = total / n;
51+
52+
// Create a functor that can be used to generate the sum of squares
53+
// for our above mean
54+
simd_ssq functor(avg);
55+
56+
// Generate a SIMD pack to hold intermediate
57+
// values of our computation (ensure it is zero-initialized)
58+
packed_type accumulated(0);
59+
60+
// Get 'raw' iterators to the underlying data
61+
double* it = REAL(data);
62+
double* end = REAL(data) + n;
63+
64+
// Loop over chunks of our data, and compute the sum of squares
65+
while (it != end)
66+
{
67+
// Load the data
68+
packed_type loaded = load<packed_type>(it);
69+
70+
// Compute the sum of squares
71+
accumulated += functor(loaded);
72+
73+
// Advance our iterator to the next 'chunk' of data
74+
it += packed_type::static_size;
75+
}
76+
77+
// Finish off by summing the accumulated values and dividing
78+
// by (n - 1)
79+
return sum(accumulated) / (n - 1);
80+
81+
}
82+
83+
/*** R
84+
x <- rnorm(1E6)
85+
var(x)
86+
simdVar(x)
87+
microbenchmark::microbenchmark(var(x), simdVar(x))
88+
*/

0 commit comments

Comments
 (0)