【问题标题】:How to see the source code of R .Internal or .Primitive function?如何查看 R .Internal 或 .Primitive 函数的源代码?
【发布时间】:2012-12-11 17:04:48
【问题描述】:

这些都没有显示pnorm函数的源代码,

stats:::pnorm
getAnywhere(pnorm)  

如何查看pnorm的源码?

sum
 (..., na.rm = FALSE)  .Primitive("sum")
.Primitive("sum")
function (..., na.rm = FALSE)  .Primitive("sum")
methods(sum)
no methods were found

还有,我如何查看sum 函数的源代码?

【问题讨论】:

    标签: r


    【解决方案1】:

    pnorm的R源码为:

    function (q, mean = 0, sd = 1, lower.tail = TRUE, log.p = FALSE) 
    .Call(C_pnorm, q, mean, sd, lower.tail, log.p)
    

    所以,从技术上讲,输入“pnorm”确实会显示源代码。然而,更有用的是:pnorm 的核心是用 C 编码的,所以上一个问题view source code in R 中的建议只是外围有用(大部分集中在隐藏在命名空间等中的函数上)。

    Uwe Ligges 的 article in R news(第 43 页)是一个很好的通用参考。从该文件:

    查看 R 源代码时,有时会调用 出现以下函数之一:.C(), .Call()、.Fortran()、.External() 或 .Internal() 和.Primitive()。这些函数调用已编译代码(如共享对象)中的入口点, 静态库或动态链接库。所以, 如果完全理解代码,则有必要查看编译代码的来源 必需的。 ... 第一步是查找 文件‘$R HOME/src/main/names.c’中的入口点,如果 调用 R 函数是 .Primitive() 或 。内部的()。 这是在以下示例中为实现“简单”R 函数的代码完成的 总和()。

    (之所以添加重点,是因为您询问的确切功能 (sum) 已在 Ligges 的文章中介绍。)

    根据您想深入研究代码的程度,可能值得下载和 按照 Ligges 的建议解压缩源代码(例如,您可以使用命令行工具 如grep通过源码搜索)。如需更随意的检查,您可以查看 通过 R Subversion serverWinston Chang's github mirror 在线获取资源(此处的链接专门指向 src/nmath/pnorm.c)。 (猜测正确的位置,src/nmath/pnorm.c,需要熟悉 R 源代码的结构。)

    meansum 都在summary.c 中实现。

    【讨论】:

    • 它与pnorm 属于不同的类别。对于 R 代码,请尝试 mean.default,对于 C 代码,请尝试 github.com/wch/r-source/blob/trunk/src/main/summary.c。并阅读上面链接的 Uwe Ligges 的文章!
    • 只是为了跟进这个答案:可能也需要注意 C 或 Fortran 中的确切函数名称。示例:我试图查找stl 的来源,它调用此行:z <- .Fortran(C_stl, x, n, as.integer(period), as.integer(s.window)。所以我通过关键字C_stl搜索了上面链接的Github镜像,但无济于事。但是,当我搜索 stl 时,有一个名为 stl.f 的文件是我想要找到的。要点是 .c 或 .f 文件名可能与被调用的函数名不完全相同。
    • 我们什么时候应该使用 .Internal?
    • @skan,我不明白这个问题。最终用户基本上应该从不使用.Internal(我已经大量使用R 大约20 年了,并且从未在我的代码中使用过它,我记得...)。如果您有更具体/有针对性的问题,请随时发布新问题...
    【解决方案2】:
    > methods(mean)
    [1] mean.data.frame mean.Date       mean.default    mean.difftime   mean.IDate*    
    [6] mean.POSIXct    mean.POSIXlt    mean.yearmon*   mean.yearqtr*  
    
       Non-visible functions are asterisked
    > mean.default
    function (x, trim = 0, na.rm = FALSE, ...) 
    {
        if (!is.numeric(x) && !is.complex(x) && !is.logical(x)) {
            warning("argument is not numeric or logical: returning NA")
            return(NA_real_)
        }
        if (na.rm) 
            x <- x[!is.na(x)]
        if (!is.numeric(trim) || length(trim) != 1L) 
            stop("'trim' must be numeric of length one")
        n <- length(x)
        if (trim > 0 && n) {
            if (is.complex(x)) 
                stop("trimmed means are not defined for complex data")
            if (any(is.na(x))) 
                return(NA_real_)
            if (trim >= 0.5) 
                return(stats::median(x, na.rm = FALSE))
            lo <- floor(n * trim) + 1
            hi <- n + 1 - lo
            x <- sort.int(x, partial = unique(c(lo, hi)))[lo:hi]
        }
        .Internal(mean(x))
    }
    <bytecode: 0x155ef58>
    <environment: namespace:base>
    

    【讨论】:

    • 这似乎没有回答 OP 的原始问题(关于 pnorm),而是他们在下面关于 mean 的评论——请注意,这也属于 C 代码,在底部(请参阅下面的评论)。
    • 确实如此。而“正确答案”就是你之前给出的那个……阅读 Uwe Ligges 在 RNews 上的文章。
    【解决方案3】:

    我知道这篇文章已有 2 年的历史了,但我认为这可能对浏览此问题的某些用户有用。

    我基本上只是将我的答案复制到this other similar question,以便它可能对一些想要探索 C 源文件的 R 用户有用。

    1. 首先,通过pryr,您可以使用show_c_source 函数,该函数将在GitHub 上搜索C 源文件中的相关代码段。适用于 .Internal 和 .Primitive 函数。

      body(match.call)
      
      # .Internal(match.call(definition, call, expand.dots))
      
      pryr::show_c_source(.Internal(match.call(definition, call, expand.dots)))
      

      这会将你带到this page,表明unique.c 包含函数do_matchcall

    2. 我在names.c 文件的基础上整理了这个tab delimited file,并使用find-in-files 来确定源代码的位置。有一些函数具有特定于平台的文件,还有一些函数有多个具有相关源代码的文件。但对于其余部分,映射已经非常完善,至少对于当前版本 (3.1.2)。

    【讨论】:

    • pryr 在我尝试定位 system 的 C 代码时不起作用:pryr::show_c_source(.Internal(system(x))),我得到了 Error: Could not find entry for system
    猜你喜欢
    • 2022-01-10
    • 1970-01-01
    相关资源
    最近更新 更多