R中nextafter功能的实现

Rón*_*aly 5 floating-point r

R 中是否有任何功能实现,以便可以从给定的浮点数中获取下一个可表示的浮点数。这将类似于C 标准库中的nextafter函数。诸如此类的方案number + .Machine$double.eps一般不起作用。

Chr*_*den 5

不,但有两种方法可以做到:

使用 C

如果您想要函数的确切功能nextafter(),您可以编写一个 C 函数作为函数的接口,以满足以下两个约束:

  • 该函数不返回值。所有的工作都是作为“副作用”(改变参数的值)完成的。
  • 所有的参数都是指针。甚至标量也是 R 中的向量(长度为 1)。

然后应该将该函数编译为共享库:

R CMD SHLIB foo.c
Run Code Online (Sandbox Code Playgroud)

适用于类 UNIX 操作系统。可以使用 调用共享库dyn.load("foo.so")。然后,您可以使用该.C()函数从 R 内部调用该函数

.C("foo", ...)
Run Code Online (Sandbox Code Playgroud)

从 R 调用 C 的更深入的处理是here

使用 R

number + .Machine$double.eps是要走的路,但您必须考虑边缘情况,例如 ifx - y < .Machine$double.eps或 if x == y。我会这样写函数:

nextafter <- function(x, y){
  # Appropriate type checking and bounds checking goes here
  delta = y - x
  if(x > 0){
    factor = 2^floor(log2(x)) + ifelse(x >= 4, 1, 0)
      } else if (x < 0) {
    factor = 65
  }
  if (delta > .Machine$double.eps){
    return(x + factor * .Machine$double.eps)
  } else if (delta < .Machine$double.eps){
    return(x - factor * .Machine$double.eps)
  } else {
    return(x)
  }
}
Run Code Online (Sandbox Code Playgroud)

现在,与 C 不同的是,如果您想检查整数,您可以在同一个函数中执行此操作,但您需要根据类型更改增量。

更新 对于大于 2 的数字,前面的代码没有按预期执行。有一个因素需要乘以.Machine$double.eps以使其足够大以导致数字不同。它与最近的 2 加 1 的幂有关。您可以通过以下代码了解这是如何工作的:

n <- -100
factor <- vector('numeric', 100)
for(i in 1:n){
  j = 0
  while(TRUE){
    j = j + 1
    if(i - j * .Machine$double.eps != i) break()
  }
  factor[i] = j
}  
Run Code Online (Sandbox Code Playgroud)