为什么数字1e9999...(31个9)会在R中引起问题?

4si2a6ki  于 2023-01-06  发布在  其他
关注(0)|答案(4)|浏览(217)

当在R中输入1e9999999999999999999999999999999时,R挂起并且不会响应-需要终止它。
它似乎发生在3台不同的计算机上,操作系统(Windows 7和Ubuntu)。它发生在RStudio,RGui和RScript中。
下面是一些更容易生成数字的代码:

boom <- paste(c("1e", rep(9, 31)), collapse="")
eval(parse(text=boom))

很明显,这不是一个实际问题,我没有必要用这么大的数字,这只是一个好奇心的问题。
奇怪的是,如果你尝试1e99999999999999999999999999999981e10000000000000000000000000000000(乘方加1或减1),你会得到Inf0,这个数字显然是某种边界,但是在什么和为什么之间呢?
我认为它可能是:

  • 一个浮点问题,但我认为他们最大值为1.7977e308,远远早于问题中的数字。
  • 32位整数的问题,但是2^32是4294967296,比所讨论的数字小得多。
  • 很奇怪。这是我的主流理论。

编辑:最迟截至2015-09-15,这不再导致R挂起,他们一定打了补丁。

k97glaaz

k97glaaz1#

这看起来像是解析器中的一个极端情况。XeY在第10.3.1节中描述:R Language Definition的文字常量,指向?NumericConstants以获取“当前接受格式的最新信息”。
问题似乎出在解析器如何处理指数,数字常量由NumericValue处理(main/gram.c的第4361行),它调用mkFloatmain/gram.c的第4124行),R_atof调用main/util.c的第1584行),R_atof调用R_strtod4main/util.c的第1461行)。(所有这些操作都是从修订版60052开始的。)
main/utils.c的第1464行显示expn声明为int,如果指数太大,它将在第1551行溢出。有符号整数溢出导致未定义的行为。
例如,下面的代码为指数〈308左右生成值,为指数〉308生成Inf

const <- paste0("1e",2^(1:31)-2)
for(n in const) print(eval(parse(text=n)))

您可以看到指数〉2^31时的未定义行为(指数= 2^31时R挂起):

const <- paste0("1e",2^(31:61)+1)
for(n in const) print(eval(parse(text=n)))

我怀疑这会引起R-core的注意,因为R只能存储大约2 e-308到2 e +308之间的数值(参见?double),而这个数字远远超过了这个数字。

368yc8dk

368yc8dk2#

这很有趣,但我认为R在解析指数非常大的数字时存在系统性问题:

> 1e10000000000000000000000000000000
[1] 0
> 1e1000000000000000000000000000000
[1] Inf
> 1e100000000000000000000
[1] Inf
> 1e10000000000000000000
[1] 0
> 1e1000
[1] Inf
> 1e100
[1] 1e+100

好了,终于有合理的解释了。根据这个输出和约书亚Ulrich下面的注解,R似乎支持表示最大为2e308的数字和解析指数最大为+2 ×10^9的数字,但它不能表示它们。在那之后,显然由于溢出而有未定义的行为。

vfh0ocws

vfh0ocws3#

  • R* 有时可能会使用bignums。也许1e9999999999999999999999999999999是某个阈值,或者解析例程阅读指数的缓冲区有限。您的观察结果与32个字符(以空结尾)的指数缓冲区一致。

我宁愿在论坛或邮件列表上问这个问题,据说这是友好的。
或者,由于 R 是自由软件,您可以研究它的源代码。

cunj1qz1

cunj1qz14#

R有时可能会使用bignums。也许1e999999999999999999999999999是某个阈值,或者也许解析例程有一个有限的缓冲区来阅读指数。您的观察结果将与32个字符(以空结尾)的指数缓冲区一致。
我宁愿在R的论坛或邮件列表上问这个问题,据说这些论坛或邮件列表很友好。
或者,由于R是自由软件,您可以研究它的源代码。

相关问题