在R中实现nextafter功能

时间:2014-02-26 16:24:11

标签: r floating-point

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

2 个答案:

答案 0 :(得分:4)

不,但有两种方法可以实现:

使用C

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

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

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

R CMD SHLIB foo.c

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

从R内部调用该函数
.C("foo", ...)

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

使用R

number + .Machine$double.eps是可行的方法,但您必须考虑边缘情况,例如x - y < .Machine$double.epsx == 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)
  }
}

现在,与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
}  

答案 1 :(得分:3)

如果您更喜欢Rcpp:

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
double nextAfter(double x, double y) {
   return nextafter(x, y);
}

然后在R:

sprintf("%.20f", 1)
#[1] "1.00000000000000000000"
sprintf("%.20f", nextAfter(1, 2))
#[1] "1.00000000000000022204"