在 C++ 函数中使用 R 函数

Using R functions within a C++ function

我正在尝试将实现黄金分割法的 R 代码转换为 C++ 代码。这是 R 代码:

goldensectionR <- function(f, dXl, dXr, dXm, dTol = 1e-9, ...) {
  
  dFr = f(dXr, ...)
  dFl = f(dXl, ...)
  dFm = f(dXm, ...)
  
  dRho = (1.0 + sqrt(5))/2.0
  
  if (dFl > dFm | dFr > dFm) {
    stop("Inital conditions are not satisfied")  
  }
  
  while (abs(dXr - dXl) > dTol) {
    
    if (dXr - dXm > dXm - dXl) {
      dY = dXm + (dXr - dXm)/(1.0 + dRho)
      dFy = f(dY, ...)
      if (dFy >= dFm) {
        dXl = dXm
        dXm = dY
      } else {
        dXr = dY  
      }
    }  else {
      dY = dXm - (dXm - dXl)/(1.0 + dRho)
      dFy = f(dY, ...)
      if (dFy >= dFm) {
        dXr = dXm
        dXm =dY
      } else {
        dXl = dY  
      }
    }   
    dFm = f(dXm, ...)  
  }
  return(dXm)
  
}

到目前为止,这是我在 C++ 中重新创建此代码的尝试:

//[[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h>
#include <Rcpp.h>

using namespace arma;
using namespace Rcpp;

// [[Rcpp::export]]
double goldensection(Function f, double dXl, double dXr, double dXm, double dTol = 1e-9) {
  
  double dFr = f(dXr);
  double dFl = f(dXl);
  double dFm = f(dXm);
  
  double dRho = (1.0 + sqrt(5))/2.0;
  
  if (dFl > dFm || dFr > dFm) {
    stop("Inital conditions are not satisfied");
  }
  
  while (fabs(dXr - dXl) > dTol) {
    
    if (dXr - dXm > dXm - dXl) {
      double dY = dXm + (dXr - dXm)/(1.0 + dRho);
      double dFy =  f(dY);
      if (dFy >= dFm) {
        dXl = dXm;
        dXm = dY;
      } else {
        dXr = dY; 
      }
    }  else {
      double dY = dXm - (dXm - dXl)/(1.0 + dRho);
      double dFy =  f(dY);
      if (dFy >= dFm) {
        dXr = dXm;
        dXm =dY;
      } else {
        dXl = dY;  
      }
    }   
    dFm = f(dXm);  
  }
  return(dXm);
    
}

f off 当然是指在 R 中定义的函数。当尝试使用 sourceCpp 将此代码导入 R 时,我在函数中使用 f 的地方出现了错误消息:

cannot convert 'SEXP' {aka 'SEXPREC*'} to 'double' in initialization

所以我显然没有在 C++ 函数中正确使用 R 函数。你如何正确地做到这一点?

问题是 Rcpp 不知道该函数会 return 一个双精度数,所以它 return 而不是一个 SEXP - 它基本上是一个包装器,可以站在对于列表、数字、字符串或其他东西。如果您确定您的 SExpr 将始终为实数,您可以使用 asReal 函数将 SEXP 转换为两倍,例如

double dFy = asReal(f(dY));