在 R 中使用整数值而不是数值(例如 1L 与 1)作为常量的好处
Benefits of using integer values for constants rather than numeric values (e.g. 1L vs 1) in R
在 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()
}
}
In most cases, the difference between an integer and a numeric value will be unimportant as R will do the right thing when using the numbers. There are, however, times when we would like to explicitly create an integer value for a constant.
- 在哪些情况下需要强制为常量设置整数值而不是简单地使用数值?例如,例如1 会失败,但例如1L 不受欢迎。
- 相反,在哪些情况下不需要使用整数值(例如交互式使用与编程、使用常量索引等)?
问题是关于良好做法和基本原理,而不是关于例如。 the "L" notation itself, the difference between integer class and numeric class, or comparing numbers.
这些是我在声明常量时明确使用 L
后缀的一些用例。当然,这些并不是严格意义上的“规范”(或唯一的),但也许您可以了解背后的基本原理。我为每种情况添加了一个“必要”标志;你会发现这些只有在你接触其他语言(如 C)时才会出现。
- 逻辑类型转换(不需要)
我没有使用经典的 as.integer
,而是使用将 0L
添加到逻辑向量以使其成为整数。当然,您可以只使用 0
,但这需要更多内存(通常是 8 个字节而不是四个字节)和转换。
- 操作returns整数(不需要)
的函数的结果
例如,您想要在 NA
之后查找以检索向量的元素。你可以:
which(is.na(vec)) + 1L
由于 which
returns 和 integer
,添加 1L
将保留类型并避免隐式转换。如果您省略 L
,则不会发生任何事情,因为它只是一个小的优化。例如,match
也会发生这种情况:如果您想 post 处理此类函数的结果,最好尽可能保留类型。
- 接口 C(必需)
来自 ?integer
:
Integer vectors exist so that data can be passed to C or Fortran
code which expects them, and so that (small) integer data can be
represented exactly and compactly.
C 在数据类型方面要严格得多。这意味着,如果将向量传递给 C 函数,则不能依赖 C 来进行转换。假设你想用某个值替换 NA 之后的元素,比如 42。你找到 NA 值在 R 级别的位置(就像我们之前用 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
以避免任何风险。 Adding/subtracting 给那个变量一个没有 L
的常量可能是进行转换的好时机。
在 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()
}
}
In most cases, the difference between an integer and a numeric value will be unimportant as R will do the right thing when using the numbers. There are, however, times when we would like to explicitly create an integer value for a constant.
- 在哪些情况下需要强制为常量设置整数值而不是简单地使用数值?例如,例如1 会失败,但例如1L 不受欢迎。
- 相反,在哪些情况下不需要使用整数值(例如交互式使用与编程、使用常量索引等)?
问题是关于良好做法和基本原理,而不是关于例如。 the "L" notation itself, the difference between integer class and numeric class, or comparing numbers.
这些是我在声明常量时明确使用 L
后缀的一些用例。当然,这些并不是严格意义上的“规范”(或唯一的),但也许您可以了解背后的基本原理。我为每种情况添加了一个“必要”标志;你会发现这些只有在你接触其他语言(如 C)时才会出现。
- 逻辑类型转换(不需要)
我没有使用经典的 as.integer
,而是使用将 0L
添加到逻辑向量以使其成为整数。当然,您可以只使用 0
,但这需要更多内存(通常是 8 个字节而不是四个字节)和转换。
- 操作returns整数(不需要) 的函数的结果
例如,您想要在 NA
之后查找以检索向量的元素。你可以:
which(is.na(vec)) + 1L
由于 which
returns 和 integer
,添加 1L
将保留类型并避免隐式转换。如果您省略 L
,则不会发生任何事情,因为它只是一个小的优化。例如,match
也会发生这种情况:如果您想 post 处理此类函数的结果,最好尽可能保留类型。
- 接口 C(必需)
来自 ?integer
:
Integer vectors exist so that data can be passed to C or Fortran code which expects them, and so that (small) integer data can be represented exactly and compactly.
C 在数据类型方面要严格得多。这意味着,如果将向量传递给 C 函数,则不能依赖 C 来进行转换。假设你想用某个值替换 NA 之后的元素,比如 42。你找到 NA 值在 R 级别的位置(就像我们之前用 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
以避免任何风险。 Adding/subtracting 给那个变量一个没有 L
的常量可能是进行转换的好时机。