Spaces:
Runtime error
Runtime error
| // Efficiently computes the simple moving average (SMA) [1] of a data series | |
| // using a parallel prefix-sum or "scan" operation. | |
| // | |
| // Note: additional numerical precision should be used in the cumulative summing | |
| // stage when computing the SMA of large data series. The most straightforward | |
| // remedy is to replace 'float' with 'double'. Alternatively a Kahan or | |
| // "compensated" summation algorithm could be applied [2]. | |
| // | |
| // [1] http://en.wikipedia.org/wiki/Moving_average#Simple_moving_average | |
| // [2] http://en.wikipedia.org/wiki/Kahan_summation_algorithm | |
| // compute the difference of two positions in the cumumulative sum and | |
| // divide by the SMA window size w. | |
| template <typename T> | |
| struct minus_and_divide : public thrust::binary_function<T,T,T> | |
| { | |
| T w; | |
| minus_and_divide(T w) : w(w) {} | |
| __host__ __device__ | |
| T operator()(const T& a, const T& b) const | |
| { | |
| return (a - b) / w; | |
| } | |
| }; | |
| template <typename InputVector, typename OutputVector> | |
| void simple_moving_average(const InputVector& data, size_t w, OutputVector& output) | |
| { | |
| typedef typename InputVector::value_type T; | |
| if (data.size() < w) | |
| return; | |
| // allocate storage for cumulative sum | |
| thrust::device_vector<T> temp(data.size() + 1); | |
| // compute cumulative sum | |
| thrust::exclusive_scan(data.begin(), data.end(), temp.begin()); | |
| temp[data.size()] = data.back() + temp[data.size() - 1]; | |
| // compute moving averages from cumulative sum | |
| thrust::transform(temp.begin() + w, temp.end(), temp.begin(), output.begin(), minus_and_divide<T>(T(w))); | |
| } | |
| int main(void) | |
| { | |
| // length of data series | |
| size_t n = 30; | |
| // window size of the moving average | |
| size_t w = 4; | |
| // generate random data series | |
| thrust::device_vector<float> data(n); | |
| thrust::default_random_engine rng; | |
| thrust::uniform_int_distribution<int> dist(0, 10); | |
| for (size_t i = 0; i < n; i++) | |
| data[i] = static_cast<float>(dist(rng)); | |
| // allocate storage for averages | |
| thrust::device_vector<float> averages(data.size() - (w - 1)); | |
| // compute SMA using standard summation | |
| simple_moving_average(data, w, averages); | |
| // print data series | |
| std::cout << "data series: [ "; | |
| for (size_t i = 0; i < data.size(); i++) | |
| std::cout << data[i] << " "; | |
| std::cout << "]" << std::endl; | |
| // print moving averages | |
| std::cout << "simple moving averages (window = " << w << ")" << std::endl; | |
| for (size_t i = 0; i < averages.size(); i++) | |
| std::cout << " [" << std::setw(2) << i << "," << std::setw(2) << (i + w) << ") = " << averages[i] << std::endl; | |
| return 0; | |
| } | |