与NumericVector的Rcpp交换功能

时间:2015-06-10 16:08:19

标签: r swap rcpp

当我在探索Rcpp时,我开始意识到以下交换功能

// swap.cpp
#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
void swap(NumericVector x) {
  double tmp = x[0];
  x[0] = x[1];
  x[1] = tmp;
}
传递整数向量时,

不执行交换。例如,

x <- 1:2
str(x)
# int [1:2] 1 2
swap(x)
x
# [1] 1 2

然而,

y <- c(1,2)
str(y)
# num [1:2] 1 2
swap(y)
y
# [1] 2 1

工作正常。我怀疑当swap传递一个整数向量x时,它被迫制作一个转换为NumericVector的x副本。然后在x的副本上执行的任何操作都不会影响传递的原始变量。这个推理是否正确?如果是这样,为什么转换必须产生副本?有没有办法编写一个更健壮的swap函数,我们不必担心在传递数字向量时偶然传递一个整数向量?

如果以前曾问过这个问题我很抱歉,但我找不到合适的答案。

编辑:

下面的代码确实显示当整数向量传递给swap而不是数字向量时,会生成对象的副本。

// [[Rcpp::export]]
void where(SEXP x) {
  Rcout << x << std::endl;
}

// [[Rcpp::export]]
void swap(NumericVector x) {
  double tmp = x[0];
  x[0] = x[1];
  x[1] = tmp;
  Rcout << "During swap function: " << x << std::endl;
}

/*** R
test_swap <- function(x) {
  cat("Before the swap function: ") 
  cat(where(x))
  swap(x)
  cat("After the swap function: ") 
  cat(where(x))
}

y <- c(1, 2) // type num
x <- 1:2 // type int

test_swap(y) // swap works because type matches function
#> Before the swap function: 0x116017bf8
#> During swap function: 0x116017bf8
#> After the swap function: 0x116017bf8

test_swap(x) // swap does not work because type does not match function
#> Before the swap function: 0x10d88e468
#> During swap function: 0x116015708
#> After the swap function: 0x10d88e468
*/

1 个答案:

答案 0 :(得分:1)

基于@ r2evans的评论,这是一个最小的实现:

#include <Rcpp.h>

template <int T>
void swap_templ(Rcpp::Vector<T> x) {
  double tmp = x[0];
  x[0] = x[1];
  x[1] = tmp;
}
// [[Rcpp::export]]
void swap(SEXP x) {
  switch (TYPEOF(x)) {
  case INTSXP: 
    swap_templ<INTSXP>(x);
    break;
  case REALSXP:
    swap_templ<REALSXP>(x);
    break;
  default:
    Rcpp::Rcout <<
      "\nInput vector must be numeric or integer type" <<
      std::endl;
    break;
  }
}

/*** R
iv <- 1L:3L
dv <- 1:3 + 0.5

R> class(iv)
[1] "integer"

R> class(dv)
[1] "numeric"

R> swap(iv); iv
[1] 2 1 3

R> swap(dv); dv
[1] 2.5 1.5 3.5

R> class(iv)
[1] "integer"

R> class(dv)
[1] "numeric"
*/