[Rcpp-devel] Rcpp ISNAN slower than C ISNAN?

Ron Wehrens ron.wehrens at gmail.com
Mon Dec 12 14:35:56 CET 2016


We are in the process of updating the kohonen package and are 
considering to move to Rcpp.

As part of this process we are running timing comparisons between the 
three ways to call C/C++ code from R. 1) using the .C interface, 2) 
using the .Call interface, and 3) using Rcpp. Here we notice something 
strange that we can capture in the following minimalistic example:

Consider the task of computing the minimal distance (sum of squares) 
between the columns of two data matrices. For this, we have an 
implementation for .C, .Call, and Rcpp (see below for the code of .Call 
and Rcpp). If we compare the timings for these three, we notice that 
Rcpp is much slower than the .C and .Call version (see the graphics at 
https://github.com/jwkruisselbrink/rcpp-timings). When checking this 
further, we notice that if the ISNAN checks are removed from all three 
versions, Rcpp catches up with the .Call version.



The questions are therefor: How can this be? What is going on with ISNAN 
in Rcpp? What can we do about it? Or are we doing something very wrong here?



Best regards,



Johannes Kruisselbrink and Ron Wehrens



Source is available here: https://github.com/jwkruisselbrink/rcpp-timings



/****************** Start Rcpp ***********************/ #include 
<Rcpp.h> using namespace Rcpp;
// [[Rcpp::export]]

double RcppDist(NumericMatrix sData1,
   NumericMatrix sData2,
   int numObjects,
   int numVars,
   int numCodes) {
   int i, j, k;
   double dist, tmp, mindist,
     *data = REAL(sData1),
     *codes = REAL(sData2);
   mindist = 10000.0;

   for (i = 0; i < numObjects; i++) {
     for (j = 0; j < numCodes; j++) {
       dist = 0;
       for (k = 0; k < numVars; k++) {
         if (!ISNAN(data[i * numVars + k])) {
           tmp = data[i * numVars + k] - codes[j * numVars + k];
           dist += tmp * tmp;
         }
       }
       if (dist < mindist) {
         mindist = dist;
       }
     }
   }

   return mindist;
}

/****************** End Rcpp ***********************/



/****************** Start Call ***********************/


#include <R.h>
#include <Rinternals.h>

SEXP CallDist(
   SEXP sData,
   SEXP sCodes,
   SEXP sNumObjects,
   SEXP sNumVars,
   SEXP sNumCodes
) {
   int
     i, j, k,
     numObjects = *INTEGER(sNumObjects),
     numCodes = *INTEGER(sNumCodes),
     numVars = *INTEGER(sNumVars);
   double
     dist, tmp, *mindist,
     *data = REAL(sData),
     *codes = REAL(sCodes);
   SEXP output = PROTECT(allocVector(REALSXP, 1));
   mindist = REAL(output);
   *mindist = 10000.0;

   for (i = 0; i < numObjects; i++) {
     for (j = 0; j < numCodes; j++) {
       dist = 0;
       for (k = 0; k < numVars; k++) {
         if (!ISNAN(data[i * numVars + k])) {
           tmp = data[i * numVars + k] - codes[j * numVars + k];
           dist += tmp * tmp;
         }
       }
       if (dist < *mindist) {
         *mindist = dist;
       }
     }
   }

   UNPROTECT(1);
   return output;
}

/****************** End Call ***********************/




More information about the Rcpp-devel mailing list