带有 NumericVector 的 Rcpp 交换函数
Rcpp swap function with NumericVector
当我探索 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
时,它被迫制作一个 x
的副本,该副本被转换为 NumericVector。然后在 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
*/
基于@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"
*/
当我探索 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
时,它被迫制作一个 x
的副本,该副本被转换为 NumericVector。然后在 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
*/
基于@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"
*/