R:如何将长数字转换为字符串以节省精度
R: How to convert long number to string to save precision
我在 R 中将长数字转换为字符串时遇到问题。如何轻松地将数字转换为字符串以保持精度?下面有一个简单的例子。
a = -8664354335142704128
toString(a)
[1] "-8664354335142704128"
b = -8664354335142703762
toString(b)
[1] "-8664354335142704128"
a == b
[1] TRUE
我预计 toString(a)
== toString(b)
,但我得到了不同的值。我想 toString()
在转换为字符串之前将数字转换为浮点数或类似的东西。
感谢您的帮助。
编辑:
> -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 中不可能获得传递给函数的 long 数字的真实值,因为 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 函数的方式,它解决了我的问题。
所以我的问题的正确答案是:
""I suppose toString() converts the number to float", 不,你自己做的(即使是无意的)。" - 不,R 自己做的,这就是 R 的读法数字。
所以我将 r2evans 的答案标记为最佳答案,因为该用户帮助我找到了正确的解决方案。谢谢!
前面的底线,您必须(在这种情况下)在转换为 64 位整数之前将大数字作为字符串读入:
bit64::as.integer64("-8664354335142704128") == bit64::as.integer64("-8664354335142703762")
# [1] FALSE
关于您尝试过的一些要点:
"I suppose toString() converts the number to float",不,是你自己做的(即使是无意的)。在 R 中,创建数字时,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"
更恰当地说,当您将其作为数字输入并然后尝试转换它时,R 首先处理括号内的内容。也就是说,用
bit64::as.integer64(-8664354335142704128)
R 首先必须解析和 "understand" 括号内的所有内容,然后才能将其传递给函数。 (这通常是一个 compiler/language-parsing 的东西,而不仅仅是一个 R 的东西。)在这种情况下,它看到它似乎是一个(大)负浮点数,所以它创建了一个 class numeric
(漂浮)。只有 then 才会将此 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 方法,可用于将不同的 formats/classes 转换为 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
仅供参考,您的数字已经接近 64 位边界:
-.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
我在 R 中将长数字转换为字符串时遇到问题。如何轻松地将数字转换为字符串以保持精度?下面有一个简单的例子。
a = -8664354335142704128
toString(a)
[1] "-8664354335142704128"
b = -8664354335142703762
toString(b)
[1] "-8664354335142704128"
a == b
[1] TRUE
我预计 toString(a)
== toString(b)
,但我得到了不同的值。我想 toString()
在转换为字符串之前将数字转换为浮点数或类似的东西。
感谢您的帮助。
编辑:
> -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 中不可能获得传递给函数的 long 数字的真实值,因为 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 函数的方式,它解决了我的问题。
所以我的问题的正确答案是:
""I suppose toString() converts the number to float", 不,你自己做的(即使是无意的)。" - 不,R 自己做的,这就是 R 的读法数字。
所以我将 r2evans 的答案标记为最佳答案,因为该用户帮助我找到了正确的解决方案。谢谢!
前面的底线,您必须(在这种情况下)在转换为 64 位整数之前将大数字作为字符串读入:
bit64::as.integer64("-8664354335142704128") == bit64::as.integer64("-8664354335142703762")
# [1] FALSE
关于您尝试过的一些要点:
"I suppose toString() converts the number to float",不,是你自己做的(即使是无意的)。在 R 中,创建数字时,
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"
更恰当地说,当您将其作为数字输入并然后尝试转换它时,R 首先处理括号内的内容。也就是说,用
bit64::as.integer64(-8664354335142704128)
R 首先必须解析和 "understand" 括号内的所有内容,然后才能将其传递给函数。 (这通常是一个 compiler/language-parsing 的东西,而不仅仅是一个 R 的东西。)在这种情况下,它看到它似乎是一个(大)负浮点数,所以它创建了一个 class
numeric
(漂浮)。只有 then 才会将此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 方法,可用于将不同的 formats/classes 转换为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
仅供参考,您的数字已经接近 64 位边界:
-.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