数值比较困难中的R(Numeric comparison difficulty in R)

2019-10-17 20:29发布

我想两个数值R作为一个if语句条件的一部分比较:

(a-b) >= 0.5

在这个特定的实例中,a = 0.58且b = 0.08 ...并且还(ab) >= 0.5是假的。 我知道使用的危害==为确切数量比较,这似乎相关:

(a - b) == 0.5)为假,而

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

我能想到的唯一的解决办法是有两个条件: (ab) > 0.5 | all.equal((ab), 0.5) (ab) > 0.5 | all.equal((ab), 0.5) 这工作,但事实是否真的唯一的解决办法? 我是不是应该戒掉的=家庭比较运营商永远的?

编辑清晰:我知道,这是一个浮点问题。 更为重要的是,我要问的是:我该怎么办呢? 什么是对付大于或-等于对R中比较切合实际的方法,因为>=不能真正信任?

Answer 1:

我从来没有去过的粉丝all.equal这样的事情。 在我看来,公差工作在有时神秘的方式。 为什么不检查较容许更大的事物小于0.05

tol = 1e-5

(a-b) >= (0.05-tol)

一般情况下,没有只用常规逻辑四舍五入,我觉得直逻辑比all.equal更好

如果x == y然后xy == 0 。 也许xy不完全是0,所以这种情况下,我使用

abs(x-y) <= tol

你必须反正设定公差all.equal这比更紧凑,更简单的all.equal



Answer 2:

如果你想经常使用这种方法,你可以创建这个作为一个独立的运营商或覆盖原> =功能(可能不是一个好主意):

# 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


Answer 3:

为了完整起见,我将指出的是,在某些情况下,你可以简单地向周围的几个小数位(这是怎样的一个跛脚的解决方案通过对比以前发布的更好的解决方案。)

round(0.58 - 0.08, 2) == 0.5


Answer 4:

选择一些公差等级:

epsilon <- 1e-10

然后使用

(a-b+epsilon) >= 0.5


Answer 5:

但是,如果您使用的公差无论如何,你为什么要关心AB = = 0.5(其实)没有得到评估? 如果你正在使用公差,反正你是说我不关心结束点完全吻合。

下面是为真,如果((AB)> = 0.5),如果((AB)<0.5)

那些每个人都应该在每对双打的评价如此。 使用一个隐含任何代码定义的另一个无操作,至少。 如果您使用的公差,以获得实际0.5包含在第一,但你的问题是你arn't完成了很多连续域中定义。 在根本问题涉及连续值大多数问题都会有非常小的点,由于在任意值0.5将始终评估,他们应该。 价值观任意接近到0.5,你正在使用适当的精度表示无所谓必去的“错误”的流量控制,但在连续的问题。

该公差有意义的唯一情况是,当你正在处理的类型的问题,如果((AB)== c)若((AB)!= C)

这里没有“合适的精度”量可以帮助你。 原因是,你必须做好准备,第二将始终为true,除非你手工非常低的水平设置AB的位的时候,其实你可能想先有时是真实的。



Answer 6:

还有一个评论。 该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’.

(手动。机页)。

换句话说,这将是对你的宽容可接受的选择:

myeq <- function(a, b, tol=.Machine$double.eps^0.5)
      abs(a - b) <= tol


Answer 7:

<=>=比较则不语言特定数值时难以浮点数上升。

IsSmallerOrEqual <- function(a,b) {   # To check a <= b
# Check whether "Mean relative difference..." exist in all.equal's result; 
# If exists, it results in character, not logical
if (   class(all.equal(a, b)) == "logical" && (a<b | all.equal(a, b))) { return(TRUE)
 } else if (a < b) { return(TRUE)
     } else { return(FALSE) }
}

IsSmallerOrEqual(abs(-2-(-2.2)), 0.2) # TRUE; To check |-2-(-2.2)| <= 0.2
IsSmallerOrEqual(abs(-2-(-2.2)), 0.3) # TRUE
IsSmallerOrEqual(abs(-2-(-2.2)), 0.1) # FALSE

IsBiggerOrEqual  <- function(a,b) {   # To check a >= b
# Check whether "Mean relative difference..." exist in all.equal's result; 
# If exists, it results in character, not logical
if (   class(all.equal(a, b)) == "logical" && (a>b | all.equal(a, b))) { return(TRUE)
 } else if (a > b) { return(TRUE)
     } else { return(FALSE) }
}
IsBiggerOrEqual(3,3) # TRUE
IsBiggerOrEqual(4,3) # TRUE
IsBiggerOrEqual(3,4) # FALSE
IsBiggerOrEqual(0.58 - 0.08,0.5)  # TRUE

如果all.equal不处理,我们可能会遇到错误。

以下是没有必要的,但有用:

abs(-2-(-2.2)) # 0.2

sprintf("%.54f",abs(-2-(-2.2)))  # "0.200000000000000177635683940025046467781066894531250000"
sprintf("%.54f",0.2)             # "0.200000000000000011102230246251565404236316680908203125"

all.equal(abs(-2-(-2.2)), 0.2)  # TRUE; check nearly equivalence of floating point numbers
identical(abs(-2-(-2.2)), 0.2)  # FALSE; check exact equivalence of floating point numbers


文章来源: Numeric comparison difficulty in R