R中的长整型/大整数/十进制等效数据类型

36

在R中,处理大数值时有哪些数据类型选择?默认情况下,整数的大小似乎是32位,因此来自SQL服务器的bigint数字以及通过rpy2从Python传递的任何大数值都会出现问题。

> 123456789123
[1] 123456789123
> 1234567891234
[1] 1.234568e+12
使用 RODBC 读取值为 123456789123456789 的 bigint 值时,返回的值是 123456789123456784(最后一位不同)。如果使用 RJSONIO 进行反序列化,那么相同的数字会被返回为 -1395630315L(这似乎是 RJSONIO 的另一个错误/限制)。
> fromJSON('[1234567891]')
[1] 1234567891
> fromJSON('[12345678912]')
[1] -539222976

实际上,我需要能够处理来自JSON的大数值,鉴于RJSONIO的限制,除了寻找更好的JSON库(目前好像不可行),我可能没有其他的解决方法。我想听听专家们对此以及一般情况下的观点。

7个回答

25

我对你的问题理解与之前两位回答者有所不同。

如果R语言中默认最大值不足以满足您的需求,您有几个选择(免责声明:下面提到的每个库我都用过,但并非通过R绑定,而是通过其他语言绑定或本机库)

Brobdingnag包:使用自然对数来存储这些值;(像Rmpfr一样,使用了R的新类结构)。我总是对需要使用这种规模数字的人印象深刻。

library(Brobdingnag)

googol <- as.brob(1e100)   

gmp包:R语言与GMP(GNU多精度库)的绑定。我在大学时用过这个库,应该已经有20年了。该库的座右铭是“算术无限制”,这是一个可信的说法——整数、有理数、浮点数等,直到你计算机内存的极限。

library(gmp)

x = as.bigq(8000, 21)
Rmpfr包:提供了与gmp和MPFR两个库的接口,(MPFR是gmp的现代实现)。我使用过Python的'bigfloat'库,强烈推荐。鉴于其范围、最活跃的维护以及最全面的文档,这可能是你最好的选择之一。
注意:要使用最后两个库中的任何一个,你需要安装原生库GMPMPFR

谢谢,但目前我对数字数据类型的限制感到满意,尽管它并没有真正回答我的问题。如果我需要处理更大的值,我会记住你的建议并研究它们。 - haridsv

23

请参阅 help(integer)

 Note that on almost all implementations of R the range of
 representable integers is restricted to about +/-2*10^9: ‘double’s
 can hold much larger integers exactly.
所以我建议使用numeric(即“double”)——双精度数字。2022年更新:这个问题仍然存在,并且不太可能改变:R中的integer是(有符号的)int32_t(因此范围受限)。一个适当的双精度数为doubleint64包通过使用S4和complex(整数)类型来提供64位分辨率(如int64_t)以克服这一点。 bit64包通过在内部使用double,并且从data.table到数据库接口或JSON解析器(包括我们的RcppSimdJson)中使用它。 我们的nanotime包依赖于它来提供基于int64_t的时间戳(即自纪元以来的纳秒)。 简而言之,没有其他方法。 一些JSON包也采用字符串表示法(“昂贵”,需要稍后转换)。

1
我查看了as.numeric()函数,但是由于mode(1)也将“numeric”作为类型返回,所以我感到困惑,认为我已经在处理它们了。然后我尝试了as.numeric("123456789123456789"),只看到打印出来的几个数字,因此我认为它失去了精度。我之前不知道options("digits")这个选项。 - haridsv
啊,没错,数字问题。此外,如果您需要更高精度或更大的数字,CRAN有相应的软件包,例如用于大数字的(奇怪命名的 :-) Brobdingnag软件包,还有与GNU gmp接口的gmp软件包。 - Dirk Eddelbuettel
(我知道Dirk知道这个,但我评论是为了提醒其他搜索者。)新版本的R允许更无缝地将整数存储转换为双精度浮点数。然而,矩阵维度仍未使用该自动模式转换。 - IRTFM

22

在这个问题被提出后,由Romain Francois开发的int64包和由Jens Oehlschlägel开发的bit64包现已可用。


2
好像int64现在已经消失了。 - evolvedmicrobe
3
@evolvedmicrobe 我们在 data.table 中使用 bit64,效果很好。 - Matt Dowle

9

Dirk是正确的。您应该使用numeric类型(应设置为双精度)。另一件需要注意的事情是,您可能无法获得所有数字。请查看位数设置:

> options("digits")
$digits
[1] 7

您可以扩展这个功能:
options(digits=14)

或者您可以重新格式化数字:

format(big.int, digits=14)

我测试了你的数字,即使使用 double 数据类型也得到了相同的行为,因此可能是一个 bug:

> as.double("123456789123456789")
[1] 123456789123456784
> class(as.double("123456789123456789"))
[1] "numeric"
> is.double(as.double("123456789123456789"))
[1] TRUE

感谢指出options()和format(),它们非常有用。然而,这些选项似乎只控制数字在显示时的格式,因此不应更改使用as.double()或as.numeric()时解析数字的方式。这种行为可能是一个错误。 - haridsv
1
我认为那行不通,你正在将一个整数转换为双精度浮点数并且失去了精度,所以你将无法索引回指向该数组的位置。 - evolvedmicrobe

4
我试图寻找这个问题的解决方法已经两天了,今天终于找到了。我们的SQL数据库中有19位长的id,在以前我使用RODBC从服务器获取bigint数据。我尝试过int64和bit64,并定义了options(digits=19),但RODBC一直报错。我用RJDBC替换了RODBC,并在从SQL服务器检索bigint数据时,通过将bigint数据转换为字符串来操作SQL查询。
下面是示例代码:
#Include stats package
require(stats);
library(RJDBC);
#set the working directory
setwd("W:/Users/dev/Apps/R/Data/201401_2");

#Getting JDBC Driver
driver <- JDBC("com.microsoft.sqlserver.jdbc.SQLServerDriver", "W:/Users/dev/Apps/R/Data/sqljdbc/enu/sqljdbc4.jar");

#Connect with DB
connection <- dbConnect(driver, "jdbc:sqlserver://DBServer;DatabaseName=DB;", "BS_User", "BS_Password");
#Query string


  sqlText <- paste("SELECT DISTINCT Convert(varchar(19), ID) as ID
 FROM tbl_Sample", sep="");

#Execute query
queryResults <- dbGetQuery(connection, sqlText);

使用这种解决方案,我可以直接获取bigint数据,而无需进行任何修改,但它与RODBC不兼容。现在,SQL服务器与R的交互速度受到影响,因为RJDBC比RODBC慢,但情况并不太糟。


2
我修复了rpy2中与整数相关的几个问题(Python在需要时可以从int切换到long,但似乎R无法做到这一点。现在,整数溢出应该返回NA_integer_。
L.

1
有许多选项可用于处理R中的大数字。您也可以使用as.numeric()。但是,as.numeric()存在问题,我发现它在版本R 3.02中存在一个错误。如果您使用as.numeric()数据类型乘以数字,而这些数字产生的结果长度约为16位数字,则会得到错误结果。已经对as.numeric()的此错误进行了多次测试。
还有另一种选择。
我为R编写了两个程序,一个称为infiX,另一个称为infiXF。该库目前仅支持乘法计算。它们都可以将数字计算到精确的小数点。已经进行了100,000+次测试。infiX将处理字符串格式的数字,而infiXF将将其转换为文件系统基础。
当您将数字存储在内存中时,您受限于8-128 Gb,具体取决于您的内存。如果编译器不允许您利用所有可用资源,则有时甚至更少。当您在文本文件基础上计算数字时,可以计算硬盘大小的1/5。唯一的问题是,需要计算所需的时间。
例如,如果我正在计算1TB的数字到另一个1TB的数字。那大约有2万亿个数字。这可以在8TB的硬盘上完成。然而,我有时间进行计算吗?
InfiX for R 可以在这里找到。 http://kevinhng86.iblog.website/2017/02/21/working-with-number-infinity-multiplication-optimised-the-code-r/

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接