在Rcpp进行向下转换时发出警告?

时间:2017-08-14 14:37:52

标签: r rcpp downcast

我有一个Rcpp函数,它应该以{{1​​}}作为输入(如IntegerVector)。我想在整数向量上使用它,但也在整数向量上使用它(例如toInt类型为1:4integer类型为1:4 + 1

然而,当这用于实际浮点数(例如double)时,我希望它返回一个警告或错误,而不是静默舍入所有值(使它们成为整数)。

1.5

2 个答案:

答案 0 :(得分:0)

Rcpp糖有你所需要的一切。这是一个可能的实现:

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
IntegerVector fprive(const RObject & x) {
    NumericVector nv(x);
    IntegerVector iv(x);
    if (is_true(any(nv != NumericVector(iv)))) warning("Uh-oh");
    return(iv);
}

/*** R
fprive(c(1.5, 2))
fprive(c(1L, 2L))
*/

其输出如下:

R> Rcpp::sourceCpp('/tmp/fprive.cpp')

R> fprive(c(1.5, 2))
[1] 1 2

R> fprive(c(1L, 2L))
[1] 1 2
Warning message:
In fprive(c(1.5, 2)) : Uh-oh
R> 

因为它是warning对象,您可以通过options("warn")控制是否要中止,立即打印,最后打印,忽略,...

答案 1 :(得分:0)

我想到的第一个解决方案

// [[Rcpp::export]]
IntegerVector toInt2(const NumericVector& x) {
  for (int i = 0; i < x.size(); i++) {
    if (x[i] != (int)x[i]) {
      warning("Uh-oh");
      break;
    }
  }
  return as<IntegerVector>(x);
}

但我想知道xIntegerVector时是否没有不必要的副本,所以我做了另一个解决方案:

// [[Rcpp::export]]
IntegerVector toInt3(const RObject& x) {
  NumericVector nv(x);
  for (int i = 0; i < nv.size(); i++) {
    if (nv[i] != (int)nv[i]) {
      warning("Uh-oh");
      break;
    }
  }
  return as<IntegerVector>(x);
}

但是,也许最好的解决方案是测试RObject是否已经是int类型,并在检查类型的同时填充结果向量:

// [[Rcpp::export]]
SEXP toInt4(const RObject& x) {
  if (TYPEOF(x) == INTSXP) return x;

  NumericVector nv(x);
  int i, n = nv.size();
  IntegerVector res(n);
  for (i = 0; i < n; i++) {
    res[i] = nv[i];
    if (nv[i] != res[i]) {
      warning("Uh-oh");
      break;
    }
  }
  for (; i < n; i++) res[i] = nv[i];

  return res;
}

一些基准测试:

x <- seq_len(1e7)
x2 <- x; x2[1] <- 1.5
x3 <- x; x3[length(x3)] <- 1.5
microbenchmark::microbenchmark(
  fprive(x),  toInt2(x),  toInt3(x),  toInt4(x),
  fprive(x2), toInt2(x2), toInt3(x2), toInt4(x2),
  fprive(x3), toInt2(x3), toInt3(x3), toInt4(x3),
  times = 20
)
Unit: microseconds
       expr        min         lq         mean     median          uq        max neval
  fprive(x) 229865.629 233539.952 236049.68870 235623.390 238500.4335 244608.276    20
  toInt2(x)  98249.764  99520.233 102026.44305 100468.627 103480.8695 114144.022    20
  toInt3(x)  50631.512  50838.560  52307.34400  51417.296  52524.0260  58311.909    20
  toInt4(x)      1.165      6.955     46.63055     10.068     11.0755    766.022    20
 fprive(x2)  63134.534  64026.846  66004.90820  65079.292  66674.4835  74907.065    20
 toInt2(x2)  43073.288  43435.478  44068.28935  43990.455  44528.1800  45745.834    20
 toInt3(x2)  42968.743  43461.838  44268.58785  43682.224  44235.6860  51906.093    20
 toInt4(x2)  19379.401  19640.198  20091.04150  19918.388  20232.4565  21756.032    20
 fprive(x3) 254034.049 256154.851 258329.10340 258676.363 259549.3530 264550.346    20
 toInt2(x3)  77983.539  79162.807  79901.65230  79424.011  80030.3425  87906.977    20
 toInt3(x3)  73521.565  74329.410  76050.63095  75128.253  75867.9620  88240.937    20
 toInt4(x3)  22109.970  22529.713  23759.99890  23072.738  23688.5365  30905.478    20

所以,toInt4似乎是最好的解决方案。