我试图比较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中大于或等于比较的合理方法,因为>=
不能真正被信任?
答案 0 :(得分:36)
对于这些事情,我从未成为all.equal
的粉丝。在我看来,宽容有时会以神秘的方式起作用。为什么不检查大于小于0.05的公差
tol = 1e-5
(a-b) >= (0.05-tol)
一般情况下,如果没有四舍五入,只使用传统逻辑,我发现直接逻辑比all.equal
更好如果x == y
则x-y == 0
。也许x-y
不完全是0所以对于这种情况我使用
abs(x-y) <= tol
您必须为all.equal
设置容差,这比all.equal
更紧凑,更直接。
答案 1 :(得分:11)
如果您想经常使用此方法,您可以将其创建为单独的运算符或覆盖原始的&gt; =函数(可能不是一个好主意):
# 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
答案 2 :(得分:6)
为了完整起见,我会指出,在某些情况下,你可以简单地舍入到几个小数位(与之前发布的更好的解决方案相比,这是一种蹩脚的解决方案。)
round(0.58 - 0.08, 2) == 0.5
答案 3 :(得分:3)
选择一些容忍度:
epsilon <- 1e-10
然后使用
(a-b+epsilon) >= 0.5
答案 4 :(得分:2)
但是,如果您仍然使用公差,为什么还要关心a-b == .5(实际上)是否未被评估?无论如何,如果你正在使用公差,你说我并不完全关心终点。
这是真的 if((a-b)&gt; = .5) if((a-b)&lt; .5)
其中一个应始终在每对双打中评估为真。任何使用一个代码的代码至少隐含地在另一个代码上定义no操作。如果您使用容差来获得实际.5包含在第一个,但您的问题是在连续域上定义的,那么您将无法完成任何工作。在涉及基础问题中持续价值的大多数问题中,没有什么意义,因为任意超过.5的值将始终按其应有的方式进行评估。任意接近.5的值将转到“错误的”流量控制,但是在使用适当精度无关紧要的连续问题中。
容差有意义的唯一时间是在处理类型问题时 if((a-b)== c) if((a-b)!= c)
这里没有“适当的精确度”可以帮助你。原因是你必须做好准备,第二个将永远评估为真,除非你手动将a-b的位设置在一个非常低的水平,而事实上你可能希望第一个有时是真的。
答案 5 :(得分:1)
还有一条评论。 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
答案 6 :(得分:1)
<=
和>=
比较不是特定于语言的。
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