简体   繁体   中英

R-Wrapper for C-Function does not work properly

currently I am introducing myself to C to extend my R-functions. I wrote a function in C for some computations and they work fine. But as soon as I write a wrapper in R itself there seems to be some mistake. Consider my C-function as "colV" and "abc" as some arbitrary matrix.

The statement (R) .Call("colV", abc, ncol(abc), nrow(abc)) works totally fine (everytime, no matter how often I use it), whereas

colV = function(x){
  nc = ncol(x)
  nr = nrow(x)
  .Call("colV", x, nc, nr)
}

delivers a wrong result at third use:

> colV(abc)
[1] 1.4274933 0.6254796 0.6774042 1.7094617 0.7250386
> colV(abc)
[1] 1.4274933 0.6254796 0.6774042 1.7094617 0.7250386
> colV(abc)
[1] -8.370087e+22  6.254796e-01  6.774042e-01  1.709462e+00  7.250386e-01

If I declare the wrapper again, the first two runs work fine and again at the third try the same result appears. Note, that besides the appearance only the first value actually changes!

Does somebody have an idea whats wrong with the wrapper? As said before, if I only use the .Call statement the correct result is returned always:

> .Call("colV", abc, ncol(abc), nrow(abc))
[1] 1.4274933 0.6254796 0.6774042 1.7094617 0.7250386
> .Call("colV", abc, ncol(abc), nrow(abc))
[1] 1.4274933 0.6254796 0.6774042 1.7094617 0.7250386
> .Call("colV", abc, ncol(abc), nrow(abc))
[1] 1.4274933 0.6254796 0.6774042 1.7094617 0.7250386
> .Call("colV", abc, ncol(abc), nrow(abc))
[1] 1.4274933 0.6254796 0.6774042 1.7094617 0.7250386
> .Call("colV", abc, ncol(abc), nrow(abc))
[1] 1.4274933 0.6254796 0.6774042 1.7094617 0.7250386
> .Call("colV", abc, ncol(abc), nrow(abc))
[1] 1.4274933 0.6254796 0.6774042 1.7094617 0.7250386

Also, I haven't had this problem using the .C-Interface, however that is not a solution to me due to speed and memory. Thanks in Advance Erin

Edit: Here is the C-Code:

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


SEXP colV(SEXP y, SEXP n, SEXP r){
    int *nc = INTEGER(n);
    double *x = REAL(y);
    int d = length(y);
    int *nr = INTEGER(r);
    int i, j, z;
    //int d = nr * nc;
    double colMean[(*nc)];
    double xSq[(d)];
    double colMsq[(*nc)];
    double xSm[(*nc)];
    SEXP result;
    PROTECT(result = allocVector(REALSXP, (*nc)));
    memset(REAL(result), 0, (*nc) * sizeof(double));
    double *colVar = REAL(result);
    //PROTECT(colVar = NEW_DOUBLE(nc));
    int fr = ((*nr) - 1);


    for(z = 0; z < (d); z++){
        xSq[z] = x[z] * x[z];
    }

    for(i = 0; i < (*nc); i++){
        for(j = 0; j < (*nr); j++){
            colMean[i] += (x[(j + ((*nr) * i)) ]);
            xSm[i] += (xSq[(j + (*nr * i))]);
        }
        colMean[i] = (colMean[i] / (*nr));
        colMsq[i] = (*nr) * (colMean[i] * colMean[i]);
        colVar[i] = ((xSm[i] - colMsq[i]) / fr);
    }
    UNPROTECT(1);
    return(result);
}

EDIT: As said in a comment, this (below) works, however for another different c-Function the same problem occurs. Using .Call directly delivers expected result, whereas putting .Call in a wrapper comes up with something wrong. I still haven't found out why.

I found the solution to the problem now, however I don't understand why it is the solution. If anybody can explain this, feel free to do so!

Changing the calculation of the colMean part in the loop was changing everything:

...
for(i = 0; i < (*nc); i++){
        for(j = 0; j < (*nr); j++){
            colMean[i] += ((x[(j + ((*nr) * i)) ]) / (*nr));
            xSm[i] += (xSq[(j + (*nr * i))]);
        }
        //colMean[i] = (colMean[i] / (*nr));
        colMsq[i] = (*nr) * (colMean[i] * colMean[i]);
        colVar[i] = ((xSm[i] - colMsq[i]) / fr);
    }
...

So moving the division by nr directly into the addition-statement solves the issue.

Have a nice day/evening folks!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM