【问题标题】:Rcpp moving average - boundary error leads to fatal errorRcpp 移动平均 - 边界错误导致致命错误
【发布时间】:2018-03-20 22:08:01
【问题描述】:

我使用滚动加权移动平均函数,其代码如下所示。它通过 Rcpp 用 C++ 编码。 此功能适用于大多数时间序列,没有循环问题或类似问题。我在下面提供了一个长度为 2 的时间序列,它有时会触发致命错误。 我找不到错误的原因。

感谢您的帮助! =)

这里是 R 代码:

# Install packages
sourceCpp("partialMA.cpp")
spencer_weights=c( -3, -6, -5, 3, 21, 46, 67, 0, 67, 46, 21, 3, -5, -6, -3)
spencer_ma <- function(x) roll_mean(x,spencer_weights)

x=c(11.026420323685528,0.25933761651337001)
spencer_ma(x) # works
for(i in 1:1000) spencer_ma(x) # triggers the fatal error 

我在下面包含了我的 roll_mean 函数的 C++ 代码:

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
NumericVector roll_mean(const NumericVector& x,
                        const NumericVector& w) {

  int n = x.size();
  int w_size = w.size();
  int size = (w_size - 1) / 2;

  NumericVector res(n);
  int i, ind_x, ind_w;

  double w_sum = Rcpp::sum(w), tmp_wsum, tmp_xwsum, tmp_w;

  // beginning
  for (i = 0; i < size; i++) {
    tmp_xwsum = tmp_wsum = 0;
    for (ind_x = i + size, ind_w = w_size - 1; ind_x >= 0; ind_x--, ind_w--) {
      tmp_w = w[ind_w];
      tmp_wsum += tmp_w;
      tmp_xwsum += x[ind_x] * tmp_w;
    }
    res[i] = tmp_xwsum / tmp_wsum;
  }

  // middle
  int lim2 = n - size;
  for (; i < lim2; i++) {
    tmp_xwsum = 0;
    for (ind_x = i - size, ind_w = 0; ind_w < w_size; ind_x++, ind_w++) {
      tmp_xwsum += x[ind_x] * w[ind_w];
    }
    res[i] = tmp_xwsum / w_sum;
  }

  // end
  for (; i < n; i++) {
    tmp_xwsum = tmp_wsum = 0;
    for (ind_x = i - size, ind_w = 0; ind_x < n; ind_x++, ind_w++) {
      tmp_w = w[ind_w];
      tmp_wsum += tmp_w;
      tmp_xwsum += x[ind_x] * tmp_w;
    }
    res[i] = tmp_xwsum / tmp_wsum;
  }

  return res;
}

【问题讨论】:

  • 这可能是由于索引越界导致的分段错误(至少从第一次快速查看)。在这种情况下,R 将简单地崩溃。我怀疑原因是计算的精度。我无法提供更多信息,因为 (a) 我不确切知道您想要实现什么,并且 (b) 代码有点复杂,主要是因为变量名(例如为什么是 n 而不是 x_size)。
  • 我同意@George。此外,对于它的价值,它在 RStudio 或普通 R 下对我来说都没有崩溃,两者都在 Ubuntu 上运行。但像往常一样,最简单的解释可能会获胜,这可能是逻辑/索引错误。我们都去过那里。
  • @George 我相信没有分段错误。我测试了从 0 到 100 的所有可能大小的时间序列的函数,包括 NAs 值,并且它可以工作。事实上,最奇怪的部分是 R 总是在崩溃之前打印正确的结果(移动平均值)。
  • R 代码的前六行只是噪音。假设使用 Rcpp 的人安装了 Rcpp。专注于错误——因此将问题减少到消失为止。我们无法复制。
  • @MaxFt 我不确定您是否看到已提交的答案,但它确实“只是”一个逻辑错误。

标签: c++ r rcpp fatal-error


【解决方案1】:

A Wild Index Out of Bounds Error Appeared!

您可以通过将元素访问器从 [] 切换到 () 来查明问题。后者有一个内置的边界检查,例如在0n-1 之间是index

使用内置检查运行代码给出:

 Error in roll_mean(x, spencer_weights) : 
  Index out of bounds: [index=7; extent=2]. 

因此,所使用的索引大大超过了向量的长度。添加跟踪语句表明它的第一个循环是错误的。

#include <Rcpp.h>
// [[Rcpp::export]]
NumericVector roll_mean(const NumericVector& x,
                        const NumericVector& w) {

  int n = x.size();
  int w_size = w.size();
  int size = (w_size - 1) / 2;

  Rcpp::Rcout << n << ", w_size: " << w_size << ", size: " << size << std::endl;

  NumericVector res(n);
  int i, ind_x, ind_w;

  double w_sum = Rcpp::sum(w), tmp_wsum, tmp_xwsum, tmp_w;

  // beginning
  for (i = 0; i < size; i++) {
    tmp_xwsum = tmp_wsum = 0;

    // Fix this line
    for (ind_x = i + size, ind_w = w_size - 1; ind_x >= 0; ind_x--, ind_w--) { 
      tmp_w = w(ind_w);
      Rcpp::Rcout << "Loop at: " << ind_w << std::endl;
      tmp_wsum += tmp_w;
      tmp_xwsum += x(ind_x) * tmp_w;
    }

    res(i) = tmp_xwsum / tmp_wsum;
  }

  Rcpp::Rcout << "success" << std::endl;
  return res;
}

这就是所有人!

【讨论】:

  • @coatless 再次通过强制边界检查获胜 :)
  • 谢谢!没错,如果我的时间序列小于权重向量,则循环不起作用。我会尽量解决这个问题,不要让我的功能太慢
猜你喜欢
  • 1970-01-01
  • 2017-04-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多