R基本C代码如何处理矢量化?

时间:2015-09-02 08:13:27

标签: c r

如果我们在R base source代码中查看用C编写的任何函数,我们可以看到代码非常简单,例如。

#include "nmath.h"
#include "dpq.h"

double dexp(double x, double scale, int give_log)
{
#ifdef IEEE_754
    /* NaNs propagated correctly */
    if (ISNAN(x) || ISNAN(scale)) return x + scale;
#endif
    if (scale <= 0.0) ML_ERR_return_NAN;

    if (x < 0.)
    return R_D__0;
    return (give_log ?
        (-x / scale) - log(scale) :
        exp(-x / scale) / scale);
}

如果从R:

调用该函数,则该函数被矢量化
dexp(rep(1, 5), 1:2)
## [1] 0.3678794 0.2706706 0.3678794 0.2706706 0.3678794

怎么回事?什么使它适当地矢量化?

1 个答案:

答案 0 :(得分:5)

实际上,您没有引用定义R函数的代码。在R中我们看到

> dexp
function (x, rate = 1, log = FALSE) 
.Call(C_dexp, x, 1/rate, log)
<bytecode: 0x3582cf8>
<environment: namespace:stats>

告诉我们dexp()函数是在stats包中定义的。通过一点挖掘,我们可以在统计数据中看到NAMESPACE

useDynLib(stats, .registration = TRUE, .fixes = "C_")

告诉我们,当暴露给R时,前缀C_被添加到函数名中。所以我们在stats包中寻找一个名为dexp的C函数。有两个相关条目

init.c:147:    CALLDEF_MATH2_1(dexp),
distn.c:144:DEFMATH2_1(dexp)

第一个是使C函数可用于R的宏,第二个是定义函数的宏。对于后者,宏被定义为

#define DEFMATH2_1(name) \
    SEXP do_##name(SEXP sa, SEXP sb, SEXP sI) { \
        return math2_1(sa, sb, sI, name); \
    }

告诉我们要查找math2_1函数,稍微向上一点

static SEXP math2_1(SEXP sa, SEXP sb, SEXP sI, double (*f)(double, double, int))
{
    SEXP sy;
    R_xlen_t i, ia, ib, n, na, nb;
    double ai, bi, *a, *b, *y;
    int m_opt;
    int naflag;

    if (!isNumeric(sa) || !isNumeric(sb))
    error(R_MSG_NONNUM_MATH);

    SETUP_Math2;
    m_opt = asInteger(sI);

    mod_iterate(na, nb, ia, ib) {
//  if ((i+1) % NINTERRUPT) R_CheckUserInterrupt();
    ai = a[ia];
    bi = b[ib];
    if_NA_Math2_set(y[i], ai, bi)
    else {
        y[i] = f(ai, bi, m_opt);
        if (ISNAN(y[i])) naflag = 1;
    }
    }
    FINISH_Math2;
    return sy;
} /* math2_1() */

mod_iterate()调用实际上是另一个宏

#define mod_iterate(n1,n2,i1,i2) for (i=i1=i2=0; i<n; \
    i1 = (++i1 == n1) ? 0 : i1,\
    i2 = (++i2 == n2) ? 0 : i2,\
    ++i)

你可以看到,至少在信仰的眼中,C代码正在实现一个循环,所以原始问题隐含的魔法(紧凑的C代码导致矢量化计算)不存在 - 它是C级的迭代。

math2_1将最终参数视为一个函数,在本例中是原始问题中引用的dexp。此函数应用于迭代中的每个元素。