Rcpp继续为一项看似简单的任务而奔波

时间:2016-05-25 21:57:39

标签: r rcpp

我一整天都在考虑它,但仍然无法弄清楚为什么会这样。我的目标很简单:STEP1,生成函数S(h,p);步骤2,通过梯形法则对S(h,p)进行数值积分,得到新函数SS(h)。我编写了代码并通过sourceCpp来源它,它在R中成功生成了两个函数S(h,p)和SS(h)。但是当我尝试通过计算SS(1)来测试它时,R只是保持运行而且从不给出了结果,这很奇怪,因为计算量并不大。知道为什么会这样吗?

我的代码在这里:

#include <Rcpp.h>
using namespace Rcpp;

//generate the first function that gives S(h,p)           
// [[Rcpp::export]]
double S(double h, double p){
  double out=2*(h+p+h*p);
  return out;
}
//generate the second function that gives the numerically integreation of S(h,p) w.r.t p
//[[Rcpp::export]]

double SS(double h){
  double out1=0;
  double sum=0;
  for (int i=0;i<1;i=i+0.01){
    sum=sum+S(h,i);
  }
  out1=0.01/2*(2*sum-S(h,0)-S(h,1));
  return out1;
}

2 个答案:

答案 0 :(得分:5)

问题在于您正在将i视为在此声明中不是int

for (int i=0;i<1;i=i+0.01){
    sum=sum+S(h,i);
}

在每次迭代之后,您尝试将0.01添加到一个整数,当然会立即将其截断为0,这意味着i总是等于零,并且您有一个无限循环。一个突出问题的最小例子,有几个可能的解决方案:

#include <Rcpp.h>

// [[Rcpp::export]]
void bad_loop() {
    for (int i = 0; i < 1; i += 0.01) {
        std::printf("i = %d\n", i);
        Rcpp::checkUserInterrupt();
    }
}

// [[Rcpp::export]]
void good_loop() {
    for (int i = 0; i < 100; i++) {
        std::printf("i = %d\n", i);
        Rcpp::checkUserInterrupt();
    }
}

// [[Rcpp::export]]
void good_loop2() {
    for (double j = 0.0; j < 1.0; j += 0.01) {
        std::printf("j = %.2f\n", j);
        Rcpp::checkUserInterrupt();
    }
}

第一个替代方法(good_loop)是适当地缩放步长 - 从0到99循环1需要相同的迭代次数,循环次数从0到0.99乘以0.01。此外,您可以使用double代替int,例如good_loop2。无论如何,这里的主要内容是你需要更加谨慎地选择C ++中的变量类型。与R不同,当您将i声明为int 时,它将被视为int ,而不是浮点数。

答案 1 :(得分:0)

正如@nrussell非常熟练地指出的那样,当持有的类型为i时,将int视为double存在问题。发布此答案的目的是强调需要避免使用doublefloat作为循环增量器。我选择将其作为答案发布而不是评论可读性。

请注意,由于精度问题,循环增量应 作为doublefloat。例如自i = .99以后...... {/ p>很难得到i = 0.981111111

相反,我会选择将循环作为int进行处理,并尽快将其转换为double / float,例如

for (int i=0; i < 100; i++){
    // Make sure to use double division 
    // (e.g. either numerator or denominator is a floating / double) 
    sum += S(h, i/100.0);
}

补充说明:

RcppArmadillo and C++ division issue

Using float / double as a loop variable