R中的数字比较难度

Mat*_*ker 42 floating-point comparison r comparison-operators r-faq

我试图比较R中的两个数字作为if语句条件的一部分:

(a-b) >= 0.5

在这个特定的例子中,a = 0.58和b = 0.08 ......但仍然(a-b) >= 0.5是假的.我知道使用==确切数字比较的危险,这似乎有关:

(a - b) == 0.5) 是假的,而

all.equal((a - b), 0.5) 是真的.

我能想到的唯一解决方案是有两个条件:(a-b) > 0.5 | all.equal((a-b), 0.5).这有效,但这真的是唯一的解决方案吗?我应该=永远地宣誓比较运营商的家庭吗?

为清晰起见编辑:我知道这是一个浮点问题.更重要的是,我要问的是:我该怎么做呢?什么是处理R中大于或等于比较的合理方法,因为>=它不能真正被信任?

Joh*_*ohn 39

我从来都不喜欢all.equal这样的事情.在我看来,宽容有时会以神秘的方式起作用.为什么不检查大于公差小于0.05的东西

tol = 1e-5

(a-b) >= (0.05-tol)
Run Code Online (Sandbox Code Playgroud)

一般来说,没有舍入和只有传统的逻辑,我发现直接逻辑比all.equal更好

如果x == y那么x-y == 0.x-y对于我使用的这种情况,也许不完全是0

abs(x-y) <= tol
Run Code Online (Sandbox Code Playgroud)

无论如何你必须设置公差all.equal,这比它更紧凑和简单all.equal.

  • “all.equal”有什么问题?它使用[一个相当合理的默认值](/sf/answers/665599091/)——eps的平方根。是的,有时需要更大的公差,但您也可以指定这些公差。 (2认同)

Sha*_*ane 12

如果要经常使用此方法,可以将其创建为单独的运算符或覆盖原始的> =函数(可能不是一个好主意):

# using a tolerance
epsilon <- 1e-10 # set this as a global setting
`%>=%` <- function(x, y) (x + epsilon > y)

# as a new operator with the original approach
`%>=%` <- function(x, y) (all.equal(x, y)==TRUE | (x > y))

# overwriting R's version (not advised)
`>=` <- function(x, y) (isTRUE(all.equal(x, y)) | (x > y))

> (a-b) >= 0.5
[1] TRUE
> c(1,3,5) >= 2:4
[1] FALSE FALSE  TRUE
Run Code Online (Sandbox Code Playgroud)

  • 我个人认为这是最好的方法,因为您不必自己决定epsilon。您甚至可以从Perl上浏览一个页面,并给它们起诸如`ge`,`le`和`ne`之类的名称。 (2认同)

ici*_*cio 9

为了完整起见,我会指出,在某些情况下,你可以简单地舍入到几个小数位(与之前发布的更好的解决方案相比,这是一种蹩脚的解决方案.)

round(0.58 - 0.08, 2) == 0.5
Run Code Online (Sandbox Code Playgroud)

  • 我认为这是最好的解决方案,对于原始问题,我将使用`round(ab,10)> = 0.5`(10位数应该足以用于将来的扩展). (3认同)

Jan*_*ary 7

再一评论。该all.equal是一个通用的。对于数值,它使用all.equal.numeric. 对该函数的检查表明它使用了.Machine$double.eps^0.5,其中.Machine$double.eps定义为

double.eps: the smallest positive floating-point number ‘x’ such that
          ‘1 + x != 1’.  It equals ‘double.base ^ ulp.digits’ if either
          ‘double.base’ is 2 or ‘double.rounding’ is 0; otherwise, it
          is ‘(double.base ^ double.ulp.digits) / 2’.  Normally
          ‘2.220446e-16’.
Run Code Online (Sandbox Code Playgroud)

(.Machine 手册页)。

换句话说,对于您的容忍度来说,这将是一个可以接受的选择:

myeq <- function(a, b, tol=.Machine$double.eps^0.5)
      abs(a - b) <= tol
Run Code Online (Sandbox Code Playgroud)