为什么数字1e9999 ...(31 9s)导致R出现问题?

seb*_*n-c 37 r

当进入1e9999999999999999999999999999999R时,R挂起并且不会响应 - 要求它被终止.

它似乎发生在3种不同的计算机上,操作系统(Windows 7和Ubuntu).它发生在RStudio,RGui和RScript中.

以下是一些可以更轻松地生成数字的代码:

boom <- paste(c("1e", rep(9, 31)), collapse="")
eval(parse(text=boom))
Run Code Online (Sandbox Code Playgroud)

现在显然这不是一个实际问题.我没有必要使用这么大的数字.这只是好奇心的问题.

奇怪的是,如果你尝试1e99999999999999999999999999999981e10000000000000000000000000000000(加上或减去一个从幂),你会得到Inf0分别.这个数字显然是某种界限,但是在这里和为什么之间?

我认为它可能是:

  • 一个浮点问题,但我认为它们最终在1.7977e308,早在有问题的数字之前.
  • 32位整数的问题,但是2 ^ 32是4294967296,远小于有问题的数字.
  • 真的很奇怪.这是我的主导理论.

编辑:最迟在2015-09-15,这不再导致R挂起.他们必须修补它.

Jos*_*ich 24

这看起来像解析器中的极端情况.该XeY格式在第10.3.1节:R语言定义的文字常量中描述,并指向?NumericConstants"当前接受的格式的最新信息".

问题似乎是解析器如何处理指数.数字常量由NumericValue(第4361行main/gram.c)处理,其调用mkFloat(第4124行main/gram.c),调用R_atof(第1584行main/util.c),调用R_strtod4(第1461行main/util.c).(全部自版本60052起.)

main/utils.c演出的第1464行显示expnint,如果指数太大,它将在第1551行溢出.带符号的整数溢出会导致未定义的行为.

例如,下面的代码为exponents <308左右和Infexponents> 308 产生值.

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

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

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

我怀疑这会得到R型铁芯任何关注,因为R可只有约2E-308之间的存储数值到2E + 308(见图?double),这个数字是方式不止于此.

  • 我希望*任何*溢出,无论在什么情况下,都会被认为是值得的. (4认同)
  • @ sebastian -c:问题应该出现在任何指数> 2147483647.我实际上得到了1e2147483647`和`1e2147483648 = 0`的挂起,而`1e2147483646 = Inf`(正如预期的那样). (2认同)
  • 我想我可以看到31 9的特别之处.它正好少于10 ^ 32而10则有2作为因子.所以有一个2 ^ 32在等待引起麻烦.999999999999999999999999999999999溢出后为2 ^ 31-1,即2147483647.溢出的结果是模数,或重复整数除法后的余数.(10 ^ 31-1)/(2 ^ 32)=(2 ^ 31*5 ^ 31)/ 2 ^ 32 - 1/2 ^ 32 = 5 ^ 31/2 - 1/2 ^ 32 =(5 ^ 31 -1)+ 1/2 - 1/2 ^ 32.取掉5 ^ 31-1叶的商(2 ^ 31-1)/ 2 ^ 32的小数部分,其为2 ^ 31-1或2147483647的余数. (2认同)

Joh*_*tts 7

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

> 1e10000000000000000000000000000000
[1] 0
> 1e1000000000000000000000000000000
[1] Inf
> 1e100000000000000000000
[1] Inf
> 1e10000000000000000000
[1] 0
> 1e1000
[1] Inf
> 1e100
[1] 1e+100
Run Code Online (Sandbox Code Playgroud)

我们去了,最后是合理的.根据这个输出和下面的Joshua Ulrich的评论,R似乎支持表示大约2e308的数字并且用指数解析数字大约+ 2*10 ^ 9,但它不能代表它们.之后,由于溢出,显然存在未定义的行为.

  • 它可以用指数+/- 2*10 ^ 9 _parse_数值常量,但它不能_represent_它们因为双精度值被限制在大约2e-308到2e + 308(参见`?double`). (2认同)
  • 我不会说它正确解析它们.表示在+ Inf和0之间保持变化,仅取决于指数中的位数.如果它正确解析它将拒绝输入或将所有这些输入映射到+ Inf. (2认同)