Skip to content

Commit 7ad5f68

Browse files
committed
example using 'simdTransformAndReduce'
1 parent f32e689 commit 7ad5f68

File tree

2 files changed

+59
-64
lines changed

2 files changed

+59
-64
lines changed

gallery/simd-variance.cpp

Lines changed: 30 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -5,84 +5,50 @@ using namespace RcppParallel;
55
#include <Rcpp.h>
66
using namespace Rcpp;
77

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
8+
class VarianceTransformer : public SimdTransformer<double>
189
{
1910
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_);
11+
packed_type initialize(const value_type* begin, const value_type* end)
12+
{
13+
n_ = end - begin;
14+
mean_ = boost::simd::accumulate(begin, end, 0.0, plus()) / n_;
15+
return packed_type(0);
2516
}
2617

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;
18+
void update(const packed_type& data, packed_type* pBuffer)
19+
{
20+
*pBuffer += boost::simd::sqr(data - mean_);
3621
}
37-
};
38-
39-
// [[Rcpp::export]]
40-
double simdVar(NumericVector data) {
4122

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)
23+
value_type reduce(const packed_type& data)
6624
{
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;
25+
return sum(data) / (n_ - 1);
7526
}
7627

77-
// Finish off by summing the accumulated values and dividing
78-
// by (n - 1)
79-
return sum(accumulated) / (n - 1);
28+
private:
8029

30+
struct plus
31+
{
32+
template <typename T>
33+
T operator()(const T& lhs, const T& rhs)
34+
{
35+
return lhs + rhs;
36+
}
37+
};
38+
39+
double mean_;
40+
std::size_t n_;
41+
};
42+
43+
// [[Rcpp::export]]
44+
double simdVar(NumericVector data) {
45+
return simdTransformAndReduce(data.begin(), data.end(), VarianceTransformer());
8146
}
8247

8348
/*** R
8449
x <- rnorm(1E6)
8550
var(x)
8651
simdVar(x)
87-
microbenchmark::microbenchmark(var(x), simdVar(x))
52+
result <- microbenchmark::microbenchmark(var(x), simdVar(x))
53+
print(result, unit = "relative")
8854
*/

inst/include/RcppParallel/SIMD.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,33 @@
2929

3030
#include <boost/simd/swar/swar.hpp>
3131

32+
33+
34+
35+
36+
37+
namespace RcppParallel {
38+
39+
template <typename DataType>
40+
class SimdTransformer
41+
{
42+
public:
43+
typedef DataType value_type;
44+
typedef boost::simd::pack<DataType> packed_type;
45+
};
46+
47+
template <typename DataType, class Transformer>
48+
DataType simdTransformAndReduce(const DataType* it, const DataType* end, Transformer transformer)
49+
{
50+
using boost::simd::pack;
51+
using boost::simd::load;
52+
53+
pack<DataType> accumulated = transformer.initialize(it, end);
54+
for (; it != end; it += pack<DataType>::static_size)
55+
transformer.update(load<pack<DataType>>(it), &accumulated);
56+
return transformer.reduce(accumulated);
57+
}
58+
59+
} // namespace RcppParallel
60+
3261
#endif /* RCPP_PARALLEL_SIMD_H */

0 commit comments

Comments
 (0)