R 如果遇到非有限值(NA、NaN或Inf),如何强制执行错误

R 如果遇到非有限值(NA、NaN或Inf),如何强制执行错误,r,debugging,conditional,nan,R,Debugging,Conditional,Nan,Matlab中有一个条件调试标志我忽略了:dbstop if infnan。如果设置,当遇到Inf或NaN时,此条件将停止代码执行(IIRC,Matlab没有NAs) 如何在R中以比在每次赋值操作后测试所有对象更有效的方式实现这一点 目前,我认为实现这一点的唯一方法是通过以下黑客: 在可能遇到这些值的所有位置之后手动插入测试(例如,除法,其中可能出现0除法)。测试将在每个元素上使用is.finite() 使用body() 修改R的源代码(?!?) 尝试使用traceem识别已更改的变量,并仅检查

Matlab中有一个条件调试标志我忽略了:
dbstop if infnan
。如果设置,当遇到
Inf
NaN
时,此条件将停止代码执行(IIRC,Matlab没有NAs)

如何在R中以比在每次赋值操作后测试所有对象更有效的方式实现这一点

目前,我认为实现这一点的唯一方法是通过以下黑客:

  • 在可能遇到这些值的所有位置之后手动插入测试(例如,除法,其中可能出现0除法)。测试将在每个元素上使用
    is.finite()
  • 使用
    body()
  • 修改R的源代码(?!?)
  • 尝试使用
    traceem
    识别已更改的变量,并仅检查这些变量是否存在错误值
  • (新增-请参见注释2)使用某种调用处理程序/回调调用测试函数
  • 第一个选择是我目前正在做的事情。这很无聊,因为我不能保证我已经检查过了所有的东西。第二个选项将测试所有内容,即使对象尚未更新。这是对时间的极大浪费。第三个选项涉及修改NA、NaN和无限值(+/-Inf)的赋值,以便产生错误。这似乎是最好的左R核心。第四个选项与第二个类似——我需要调用一个单独的函数,列出所有的内存位置,只需标识那些已更改的位置,然后检查值;我甚至不确定这是否适用于所有对象,因为程序可能会进行就地修改,这似乎不会调用
    duplicate
    函数

    有没有我错过的更好的方法?也许是马克·布拉文顿(Mark Bravington)、卢克·蒂尔尼(Luke Tierney)的一些聪明的工具,或者是一些相对基本的东西——类似于编译R时的
    options()
    参数或标志

    示例代码下面是一些非常简单的示例代码,用于测试,其中包含了Josh O'Brien提出的
    addTaskCallback
    函数。代码不会中断,但在第一种情况下会发生错误,而在第二种情况下不会发生错误(即
    badDiv(0,0,FALSE)
    不会中止)。我仍在调查回调,因为这看起来很有希望

    badDiv  <- function(x, y, flag){
        z = x / y
        if(flag == TRUE){
            return(z)
        } else {
            return(FALSE)
        }
    }
    
    addTaskCallback(stopOnNaNs)
    badDiv(0, 0, TRUE)
    
    addTaskCallback(stopOnNaNs)
    badDiv(0, 0, FALSE)
    

    badDiv恐怕没有这样的捷径。从理论上讲,在unix上有
    SIGFPE
    ,您可以利用它,但实际上是这样的

  • 没有标准的方法来启用FP操作来捕获它(即使C99也不包括这方面的规定)-它是高度系统特定的(例如Linux上的
    feenableexcept
    ,AIX上的
    FP\u enable\u all
    等等),或者需要为目标CPU使用汇编程序
  • 如今,FP操作通常以向量单位(如SSE)进行,因此您甚至无法确定FPU是否参与其中
  • R截取一些操作,比如
    NaN
    s、
    NA
    s,并分别处理它们,这样它们就不会进入FP代码
  • 也就是说,如果您足够努力(禁用SSE等),您可以攻击自己的R,它将捕获平台和CPU的一些异常。这不是我们会考虑建立R,而是为了一个特殊的目的,它可能是可行的。 但是,除非您更改R内部代码,否则它仍然无法捕获
    NaN
    /
    NA
    操作。此外,您必须检查正在使用的每个包,因为它们可能在其C代码中使用FP操作,也可能单独处理
    NA
    /
    NaN

    如果您只担心被零除或过流/下流之类的问题,那么上面的方法会起作用,并且可能是最接近解决方案的方法

    仅仅检查您的结果可能不太可靠,因为您不知道结果是否基于某个中间
    NaN
    计算,该计算更改了聚合值,该值可能不需要也是
    NaN
    。如果您愿意放弃这种情况,那么您可以简单地递归地遍历结果对象或工作区。这不应该是非常低效的,因为您只需要担心
    REALSXP
    ,而不需要担心其他任何事情(除非您也不喜欢
    NA
    s,否则您会有更多的工作)


    这是一个可用于递归遍历R对象的示例代码:

    static int do_isFinite(SEXP x) {
        /* recurse into generic vectors (lists) */
        if (TYPEOF(x) == VECSXP) {
            int n = LENGTH(x);
            for (int i = 0; i < n; i++)
                if (!do_isFinite(VECTOR_ELT(x, i))) return 0;
        }
        /* recurse into pairlists */ 
        if (TYPEOF(x) == LISTSXP) {
             while (x != R_NilValue) {
                 if (!do_isFinite(CAR(x))) return 0;
                 x = CDR(x);
             }
             return 1;
        }
        /* I wouldn't bother with attributes except for S4
           where attributes are slots */
        if (IS_S4_OBJECT(x) && !do_isFinite(ATTRIB(x))) return 0;
        /* check reals */
        if (TYPEOF(x) == REALSXP) {
            int n = LENGTH(x);
            double *d = REAL(x);
            for (int i = 0; i < n; i++) if (!R_finite(d[i])) return 0;
        }
        return 1; 
    }
    
    SEXP isFinite(SEXP x) { return ScalarLogical(do_isFinite(x)); }
    
    # in R: .Call("isFinite", x)
    
    static int do_isFinite(SEXP x){
    /*递归到通用向量(列表)*/
    if(TYPEOF(x)=VECSXP){
    int n=长度(x);
    对于(int i=0;i
    下面概述的想法(及其实现)非常不完善。我甚至不太愿意提出这个建议,但是:(a)我认为它有点有趣,尽管它很丑陋;(b)我能想到一些有用的情况。考虑到你现在听起来像是在每次计算后手动插入支票,我希望你的情况就是这样

    我的是两步破解。Fi
    # Sketch of a function that tests for NaNs in several types of objects
    nanDetector <- function(X) {
       # To examine data frames
       if(is.data.frame(X)) { 
           return(any(unlist(sapply(X, is.nan))))
       }
       # To examine vectors, matrices, or arrays
       if(is.numeric(X)) {
           return(any(is.nan(X)))
       }
       # To examine lists, including nested lists
       if(is.list(X)) {
           return(any(rapply(X, is.nan)))
       }
       return(FALSE)
    }
    
    # Set up the taskCallback
    stopOnNaNs <- function(...) {
        if(nanDetector(.Last.value)) {stop("NaNs detected!\n")}
        return(TRUE)
    }
    addTaskCallback(stopOnNaNs)
    
    
    # Try it out
    j <- 1:00
    y <- rnorm(99)
    l <- list(a=1:4, b=list(j=1:4, k=NaN))
    # Error in function (...)  : NaNs detected!
    
    # Subsequent time consuming code that could be avoided if the
    # error thrown above is used to stop its evaluation.