第2章 .Internal vs. Primitive ぱらぱらめくる『R Internals version 2.14.1』

  • 『R Internals version 2.14.1』の目次はこちら
  • (.Primitive と.Inetrnal) vs. (.External)
    • どちらもCやFortranの関数呼び出し
    • (.Primitive と.Inetrnal)はデフォルトで読まれる(らしい)
    • (.External)はあとから入れるパッケージで呼び出すもの
  • .Primitive vs .Internal (1)
    • .Primitive は直接C(やら)が呼ばれる
    • .InternalはCを呼びに行くという処理(この処理自体は.Primitiveな処理)を介してC(やら)の関数へと連結される
  • .Primitive vs .Internal (2)
    • .Primitive の方は「文法」的なもの(が多い/ほとんど)
    • .Internal の方はいわゆる処理関数
  • .Internalの中身を探せ
    • ソース付きバージョンをとってくると "src/main/names.c"というファイルとともに、その他のCのソースファイルがとれてくる
    • この"names.c"ファイルというのは、Rでの関数と、それに対応するCの関数が書いてある(以下のような感じ)
/* Random Numbers */

{"rchisq",	do_random1,	0,	11,	2,	{PP_FUNCALL, PREC_FN,	0}},
{"rexp",	do_random1,	1,	11,	2,	{PP_FUNCALL, PREC_FN,	0}},
{"rgeom",	do_random1,	2,	11,	2,	{PP_FUNCALL, PREC_FN,	0}},
{"rpois",	do_random1,	3,	11,	2,	{PP_FUNCALL, PREC_FN,	0}},
{"rt",		do_random1,	4,	11,	2,	{PP_FUNCALL, PREC_FN,	0}},
{"rsignrank",	do_random1,	5,	11,	2,	{PP_FUNCALL, PREC_FN,	0}},
    • したがって、Rの関数 rchisq()の中身を見ようとして以下のようにやると、.Internal()に"rchisq"が渡されているのがわかる
> rchisq
function (n, df, ncp = 0) 
{
    if (missing(ncp)) 
        .Internal(rchisq(n, df))
    else .Internal(rnchisq(n, df, ncp))
}
<bytecode: 0x018f6508>
<environment: namespace:stats>
    • .Internal()で呼ばれる関数は、"names.c"の中に定義してあるから、そのファイルを開いて、文字列検索すると、以下のような行がある
{"rchisq",	do_random1,	0,	11,	2,	{PP_FUNCALL, PREC_FN,	0}},
    • これを見て、Cのdo_random1()関数が呼び出されることが分かる
    • Cのdo_random1()関数は独立したCのソースファイルにはなっていないが、"random.c"というファイルが"src/main/"にあり、その中に、という記載があって、これが処理。パラメタが1個の分布、2個の分布に分けて関数がかき分けてあることが分かる
SEXP attribute_hidden do_random1(SEXP call, SEXP op, SEXP args, SEXP rho)
{
    SEXP x, a;
    int i, n, na;
    checkArity(op, args);
    if (!isVector(CAR(args)) || !isNumeric(CADR(args)))
	invalid(call);
    if (LENGTH(CAR(args)) == 1) {
	n = asInteger(CAR(args));
	if (n == NA_INTEGER || n < 0)
	    invalid(call);
    }
    else n = LENGTH(CAR(args));
    PROTECT(x = allocVector(REALSXP, n));
    if (n == 0) {
	UNPROTECT(1);
	return(x);
    }
    na = LENGTH(CADR(args));
    if (na < 1) {
	for (i = 0; i < n; i++)
	    REAL(x)[i] = NA_REAL;
	warning(_("NAs produced"));
    }
    else {
	Rboolean naflag = FALSE;
	PROTECT(a = coerceVector(CADR(args), REALSXP));
	GetRNGstate();
	switch (PRIMVAL(op)) {
	    RAND1(0, rchisq);
	    RAND1(1, rexp);
	    RAND1(2, rgeom);
	    RAND1(3, rpois);
	    RAND1(4, rt);
	    RAND1(5, rsignrank);
	default:
	    error(_("internal error in do_random1"));
	}
	if (naflag)
	    warning(_("NAs produced"));

	PutRNGstate();
	UNPROTECT(1);
    }
    UNPROTECT(1);
    return x;
}