在r中对常量使用整数值而不是数值(例如1L vs 1)的好处



在R源代码中,大多数(但不是全部)函数使用整数值作为常量:

colnames <- function(x, do.NULL = TRUE, prefix = "col")
{
if(is.data.frame(x) && do.NULL)
return(names(x))
dn <- dimnames(x)
if(!is.null(dn[[2L]]))
dn[[2L]]
else {
nc <- NCOL(x)
if(do.NULL) NULL
else if(nc > 0L) paste0(prefix, seq_len(nc))
else character()
}
}

R语言定义说:

在大多数情况下,整数和数值之间的区别并不重要,因为R在使用数字时将做正确的事情。然而,有时我们需要显式地为常量创建一个整数值。

  • 在这些情况下,有必要强制整数值的常量,而不是简单地使用数值?例如,例如1会失败,但例如1L不会。
  • 相反,在哪些情况下使用整数值是不必要的(例如交互式使用vs编程,索引常量等)?

这个问题是关于良好实践和基本原理的,而不是关于例如"L"符号本身,整数类和数字类的区别,或者比较数字。

这些是我在声明常量时显式使用L后缀的一些用例。当然,这些并不是严格意义上的"规范"。(或唯一的),但也许你可以知道背后的基本原理。我在每一种情况下都加上了"必要"一词。国旗;您将看到,只有当您与其他语言(如C)进行接口时,才会出现这些问题。

  • 逻辑类型转换(不需要)

不使用经典的as.integer,而是使用将0L添加到逻辑向量以使其成为整数。当然,您可以只使用0,但这将需要更多的内存(通常是8字节而不是4字节)和转换。

  • 操作返回整数的函数的结果(不需要)

例如,您想查找并检索在NA之后的向量的元素。你可以:

which(is.na(vec)) + 1L

由于which返回integer,添加1L将保留该类型并避免隐式转换。如果省略L,什么也不会发生,因为这只是一个小的优化。例如,match也会发生这种情况:如果您想对这样一个函数的结果进行后处理,那么尽可能保留该类型是一个好习惯。

  • 接口C(必要)

From?integer:

整数向量的存在使得数据可以传递给C或Fortran代码中期望它们,这样(小)整数数据就可以了精确而紧凑地表示。

C在数据类型方面要严格得多。这意味着,如果你将一个向量传递给一个C函数,你不能依赖C来进行转换。假设您想用某个值替换NA之后的元素,比如42。在R级找到NA值的位置(就像我们之前对which所做的那样),然后将原始向量和索引向量传递给C。C函数看起来像:

SEXP replaceAfterNA (SEXP X, SEXP IND) {
...
int *ind = INTEGER(IND);
...
for (i=0; i<l; i++) {
//make here the replacement
}
}

和R侧:

...
ind <- which(is.na(x)) + 1L
.Call("replaceAfterNA", x, ind)
...

如果省略上面第一行中的L,您将收到如下错误:

INTEGER() cannot be applied to double vectors

因为C需要一个整数类型

  • Java接口(必需)

同前。如果您使用rJava包并希望R调用您自己的自定义Java类和方法,则必须确保在Java方法需要整数时传递整数。这里不添加一个具体的例子,但是应该很清楚为什么在这些情况下您可能希望在常量中使用L后缀。

附录

在前面的例子中,你可能想要使用L。即使我猜不太常见,添加一个您不需要的情况也可能很有用。L。如果存在整数溢出的危险,可能会出现这种情况。*+-操作符如果两个操作数都是整型,则保留该类型。例如:

#this overflows
31381938L*3231L
#[1] NA
#Warning message:
#In 31381938L * 3231L : NAs produced by integer overflow
#this not
31381938L*3231
#[1] 1.01395e+11

所以,如果你对一个可能产生溢出的整数变量进行操作,将其强制转换为double以避免任何风险是很重要的。在没有L的情况下,为该变量添加/减去一个常量可能是进行强制转换的好时机。

相关内容

  • 没有找到相关文章

最新更新