我有一个问题是将一个长数字转换为R中的字符串。如何轻松地将数字转换为字符串以保持精度? A有一个简单的例子如下。
a = -8664354335142704128
toString(a)
[1] "-8664354335142704128"
b = -8664354335142703762
toString(b)
[1] "-8664354335142704128"
a == b
[1] TRUE
我期待toString(a)
== toString(b)
,但我有不同的价值观。我想toString()
在转换为字符串之前将数字转换为float或类似的东西。
谢谢您的帮助。
编辑:
> -8664354335142704128 == -8664354335142703762
[1] TRUE
> along = bit64::as.integer64(-8664354335142704128)
> blong = bit64::as.integer64(-8664354335142703762)
> along == blong
[1] TRUE
> blong
integer64
[1] -8664354335142704128
我也尝试过:
> as.character(blong)
[1] "-8664354335142704128"
> sprintf("%f", -8664354335142703762)
[1] "-8664354335142704128.000000"
> sprintf("%f", blong)
[1] "-0.000000"
编辑2:
我的问题首先是,如果我可以将一个长数字转换为字符串而不会丢失。然后我意识到,在R中是不可能得到一个传入函数的长数的实数值,因为R会自动读取带有损失的值。
例如,我有这个功能:
> my_function <- function(long_number){
+ string_number <- toString(long_number)
+ print(string_number)
+ }
如果有人使用它并通过了一个很长的号码,我无法获得信息,这个号码是完全通过的。
> my_function(-8664354335142703762)
[1] "-8664354335142704128"
例如,如果我从文件中读取一些数字,那很容易。但这不是我的情况。我只需要使用某些用户传递的内容。
我不是R专家,所以我很好奇为什么在另一种语言中它起作用而在R中没有。例如在Python中:
>>> def my_function(long_number):
... string_number = str(long_number)
... print(string_number)
...
>>> my_function(-8664354335142703762)
-8664354335142703762
现在我知道,问题是R如何读取和存储数字。每种语言都可以做到不同。我必须改变如何将数字传递给R函数的方式,它解决了我的问题。
所以我的问题的正确答案是:
“”我想toString()将数字转换成浮点数“,不,你自己做了(即使是无意中)。” - 不,R自己做了,这就是R读数字的方式。
因此我将r2evans的答案标记为最佳答案,因为该用户帮助我找到了正确的解决方案。谢谢!
在前面的底线,你必须(在这种情况下)在转换为64位整数之前将大数字作为字符串读取:
bit64::as.integer64("-8664354335142704128") == bit64::as.integer64("-8664354335142703762")
# [1] FALSE
关于你尝试过的一些观点:
5
是一个浮点数,而5L
是一个整数。即使您曾尝试将其创建为整数,但无论如何它都会抱怨并失去精度:
class(5)
# [1] "numeric"
class(5L)
# [1] "integer"
class(-8664354335142703762)
# [1] "numeric"
class(-8664354335142703762L)
# Warning: non-integer value 8664354335142703762L qualified with L; using numeric value
# [1] "numeric"
bit64::as.integer64(-8664354335142704128)
R首先必须解析并“理解”括号内的所有内容,然后才能将其传递给函数。 (这通常是编译器/语言解析的东西,而不仅仅是R的东西。)在这种情况下,它看到它看起来是一个(大)负浮点数,因此它创建了一个类numeric
(float)。只有这样才会将此numeric
发送给函数,但到此时精度已经丢失。因此不合逻辑
bit64::as.integer64(-8664354335142704128) == bit64::as.integer64(-8664354335142703762)
# [1] TRUE
在这种情况下,它只是*发生该数字的64位版本等于您的意图。
bit64::as.integer64(-8664254335142704128) # ends in 4128
# integer64
# [1] -8664254335142704128 # ends in 4128, yay! (coincidence?)
如果你减去一个,它会产生相同的有效integer64
:
bit64::as.integer64(-8664354335142704127) # ends in 4127
# integer64
# [1] -8664354335142704128 # ends in 4128 ?
这种情况持续了很长一段时间,直到它最终转移到下一个圆点
bit64::as.integer64(-8664254335142703617)
# integer64
# [1] -8664254335142704128
bit64::as.integer64(-8664254335142703616)
# integer64
# [1] -8664254335142703104
差异是1024或2 ^ 10不太可能是巧合。我还没有钓鱼,但我猜这里有关于32位陆地浮点精度的一些有意义的东西。bit64::as.integer64
有几种S3方法,可用于将不同的格式/类转换为integer64
library(bit64)
methods(as.integer64)
# [1] as.integer64.character as.integer64.double as.integer64.factor
# [4] as.integer64.integer as.integer64.integer64 as.integer64.logical
# [7] as.integer64.NULL
因此,bit64::as.integer64.character
可能很有用,因为当您键入或以字符串形式读取时,精度不会丢失:
bit64::as.integer64("-8664354335142704128")
# integer64
# [1] -8664354335142704128
bit64::as.integer64("-8664354335142704128") == bit64::as.integer64("-8664354335142703762")
# [1] FALSE
-.Machine$integer.max
# [1] -2147483647
-(2^31-1)
# [1] -2147483647
log(8664354335142704128, 2)
# [1] 62.9098
-2^63 # the approximate +/- range of 64-bit integers
# [1] -9.223372e+18
-8664354335142704128
# [1] -8.664354e+18