布尔运算符&&和&之间的区别||和|在R中

eulz3vhy  于 2023-04-03  发布在  其他
关注(0)|答案(4)|浏览(126)

根据R语言定义,&&&(对应|||)的区别在于前者是矢量化的,而后者不是。
根据the help text,我读到的区别类似于“And”和“AndAlso”之间的区别(相应地“Or”和“OrElse”)......含义:不是所有的求值都必须为真(即如果A为真,则A或B或C总是为真,因此如果A为真,则停止求值)
有人能解释一下吗?还有,R中有AndAlso和OrElse吗?

nbnkbykc

nbnkbykc1#

较短的是向量化的,这意味着它们可以返回一个向量,像这样:

((-2:2) >= 0) & ((-2:2) <= 0)
# [1] FALSE FALSE  TRUE FALSE FALSE

较长的形式从左到右计算,只检查每个向量的第一个元素,因此上面给出

((-2:2) >= 0) && ((-2:2) <= 0)
# [1] FALSE

正如帮助页面所述,这使得较长的形式“适合编程控制流,并且通常在if子句中更受欢迎”。
所以只有当你确定向量的长度为1时,你才想使用长形式。
你应该 * 绝对 * 确定你的向量只有长度1,例如在它们是只返回长度1的布尔值的函数的情况下。如果向量的长度可能〉1,你想使用缩写形式。所以如果你不是绝对确定,你应该首先检查,或者使用简短形式,然后使用allany将其长度缩减为1,以便在控制流语句中使用,如if
函数allany通常用于矢量化比较的结果,以分别查看所有或任何比较是否为真。这些函数的结果长度肯定为1,因此它们适合用于if子句,而矢量化比较的结果则不适合。(尽管这些结果适合用于ifelse
最后一个区别:&&||只计算它们需要计算的项(这似乎就是短路的意思)。如果它没有短路,就像&|没有那样,它将给予错误。

a
# Error: object 'a' not found
TRUE || a
# [1] TRUE
FALSE && a
# [1] FALSE
TRUE | a
# Error: object 'a' not found
FALSE & a
# Error: object 'a' not found

最后,请参见The R Inferno中的8.2.17节,标题为“and and and and”。

kq0g1dla

kq0g1dla2#

关于"short-circuiting"的答案可能会引起误解,但也有一定的道理在R/S语言中,&&||只计算第一个参数中的第一个元素。向量或列表中的所有其他元素都被忽略,不管第一个元素的值是什么。这些运算符被设计成与if (cond) {} else{}构造一起工作,并指导程序控制,而不是构造新的向量。&|运算符被设计用于向量,因此它们将“并行”应用,也就是说,沿着最长参数的长度。在进行比较之前,需要对两个向量进行求值。如果向量的长度不同,则执行较短参数的循环。
当对&&||的参数求值时,存在“短路”,因为如果从左到右连续的任何值是决定性的,则求值停止并返回最终值。

> if( print(1) ) {print(2)} else {print(3)}
[1] 1
[1] 2
> if(FALSE && print(1) ) {print(2)} else {print(3)} # `print(1)` not evaluated
[1] 3
> if(TRUE && print(1) ) {print(2)} else {print(3)}
[1] 1
[1] 2
> if(TRUE && !print(1) ) {print(2)} else {print(3)}
[1] 1
[1] 3
> if(FALSE && !print(1) ) {print(2)} else {print(3)}
[1] 3

短路的优点只会在参数需要很长时间才能求值时出现。这通常发生在参数是处理更大对象或具有更复杂数学运算的函数时。
更新:最新版本的news(“R”)说,为&&||提供长度大于1的向量已被弃用,并发出警告,RCore的目的是在后续版本的R中将其作为错误。

wko9yo5t

wko9yo5t3#

&&||是所谓的“短路”。这意味着如果第一个操作数足以确定表达式的值,它们将不会计算第二个操作数。
例如,如果&&的第一个操作数为假,那么计算第二个操作数没有意义,因为它不能改变表达式的值(false && truefalse && false都为假)。
您可以在这里阅读更多信息:http://en.wikipedia.org/wiki/Short-circuit_evaluation从该页的表中可以看到,&&等效于VB.NET中的AndAlso,我假设您指的是VB.NET。

bpsygsoo

bpsygsoo4#

运算符&&/||&/|之间有三个相关差异,在official documentation中有解释。下面是摘要:

1. &| * 矢量化 *

这意味着,如果你想对向量执行逐元素逻辑运算,你应该使用&|

a = c(TRUE, TRUE, FALSE, FALSE)
b = c(TRUE, FALSE, TRUE, FALSE)

a | b
# [1]  TRUE  TRUE  TRUE FALSE

a || b
# [1] TRUE

对于&&/||,第一个元素之后的所有元素都将被丢弃。当对长度大于1的向量使用&&/||时,R的最新版本会生成一个有用的警告:

In a || b : 'length(x) = 4 > 1' in coercion to 'logical(1)'

2. &&|| * 短路 *

短路意味着只有在表达式的左边还没有确定结果的情况下,表达式的右边才被求值。几乎每种编程语言都对条件操作这样做,因为它在编写if条件时会导致方便的习惯用法,例如:

if (length(x) > 0L && x[1L] == 42) …

此代码依赖于短路:如果没有它,如果x为空,代码将失败,因为右侧试图访问一个不存在的元素。如果没有短路,我们将不得不使用嵌套的if块,导致更冗长的代码:

if (length(x) > 0L) {
    if (x[1L] == 42) …
}

作为一般规则,在条件表达式(ifwhile)中,您应该始终使用&&||,即使不需要短路:它更符合习惯用法,并导致更统一的代码。

3. &|可以执行 * 按位算术 *

在许多编程语言中,&|实际上执行按位算术而不是布尔算术。也就是说,对于两个整数aba & b计算 * 按位和 *,a | b计算 * 按位或 *。对于布尔值,按位和逻辑运算之间没有区别;但对于任意整数,结果会有所不同。例如,大多数编程语言中的1 | 2 == 3
然而,对于R来说,这不是真的:R将&|的数值参数强制转换为逻辑值并执行布尔运算。
...除非两个参数都是raw类型:

c(1, 3) | c(2, 4)
# [1] TRUE TRUE

as.raw(c(1, 3)) | as.raw(c(2, 4))
# [1] 03 07

值得注意的是,操作!(逻辑取反)和xor在使用raw参数调用时也执行按位算术。

相关问题