在尝试优化我的代码时,我发现与 integer
或 numeric
上类似的操作相比,一些 logical
操作速度较慢。
所以我尝试将基本的布尔运算符 !
、&
、|
、xor
重写如下:
my.not <- function(x) as.logical(1L - as.integer(x))
my.and <- function(e1, e2) as.logical(as.integer(e1) * as.integer(e2))
my.or <- function(e1, e2) as.logical(as.integer(e1) + as.integer(e2))
my.xor <- function(e1, e2) as.logical(as.integer(e1) + as.integer(e2) == 1L)
测试一切是否按预期工作:
a <- sample(c(TRUE, FALSE), 1e6, TRUE)
b <- sample(c(TRUE, FALSE), 1e6, TRUE)
identical(!a, my.not(a)) # TRUE
identical(a & b, my.and(a, b)) # TRUE
identical(a | b, my.or(a, b)) # TRUE
identical(xor(a, b), my.xor(a, b)) # TRUE
现在正在进行基准测试:
library(microbenchmark)
microbenchmark(!a, my.not(a),
a & b, my.and(a, b),
a | b, my.or(a, b),
xor(a, b), my.xor(a, b))
# Unit: milliseconds
# expr min lq median uq max neval
# !a 1.237437 1.459042 1.463259 1.492671 17.28209 100
# my.not(a) 6.018455 6.263176 6.414515 15.291194 70.16313 100
# a & b 32.318530 32.667525 32.769014 32.973878 50.55528 100
# my.and(a, b) 8.010022 8.592776 8.750786 18.145590 78.38736 100
# a | b 32.030545 32.383769 32.506937 32.820720 102.43609 100
# my.or(a, b) 12.089538 12.434793 12.663695 22.046841 32.19095 100
# xor(a, b) 94.892791 95.480200 96.072202 106.104000 164.19937 100
# my.xor(a, b) 13.337110 13.708025 14.048350 24.485478 29.75883 100
从结果来看,!
运算符似乎是唯一一个能够与我的实现相当的。而另外三个运算符则慢了几倍,这对于 Primitive
函数来说有点尴尬。我甚至希望一个良好实现的布尔运算符应该比整数运算(我的函数实现方式)要快得多。
问题:为什么?实现不好吗?还是原始函数做了一些好事情(例如错误检查、特殊情况),而我的函数没有做到?
c(x=TRUE)
。 - Martin Morgan