【问题标题】:Is there a datatype "Decimal" in R?R中是否有数据类型“十进制”?
【发布时间】:2013-06-02 08:21:00
【问题描述】:

我从 MySQL 表中读取以 DECIMAL 格式存储的数据。我想对 R 中的这些数字进行计算。

我曾经使用as.numeric() 将它们转换为数字表示,但文档说:

numeric 与 double(和 real)相同。

但是 R 中还有数据类型 Decimal 吗? (没有舍入错误的数据类型,...)

这里有一个关于舍入错误问题的简单示例:

numbersStrings = c("0.1", "0.9")
numbersNumeric = as.numeric(numbersStrings)
numbersMirror  = c(numbersNumeric, 1-numbersNumeric)

str(numbersMirror)

numbersMirror
unique(numbersMirror)  # has two times 0.1 ...

sprintf("%.25f", numbersMirror)
sprintf("%.25f", unique(numbersMirror))  # ... because there was a rounding error

【问题讨论】:

  • 这可能有用:cran.r-project.org/web/packages/Rmpfr/index.html 这是一个在 R 中执行任意精度浮点运算的库。
  • MySQL 文档清楚地表明 DECIMAL 不是任意精度。它确实允许比“双”(53)表示的数字更多(64)。它还清楚地表明,如果小数点右侧的数字超过所选限制,则需要截断。我怀疑将双精度截断到特定限制可以满足大多数需求。
  • 很好的例子。我通过使用table() 解决了类似的问题(这里你可以使用table(numbersMirror))。表似乎四舍五入。我没有关于它如何圆的详细信息,但对于你的例子,它似乎有效。无论如何:十进制数据类型应该更精确。 (当然只适用于 -/+ 操作)。 @DWin:我认为您的意思是 round() 而不是截断。
  • @DWin, Rmpfr 可以设置为使用 64 位。我写了“任意精度”,但我的意思是“多精度”。 :-) 仅使用doubles 无法在“普通 R”中实现这一点。
  • 这将是一个要管理的 PITA,因为您需要将“数字”作为字符表示形式从 MySQL 中引入,然后转换为 Rmpfr,然后再转换回字符,然后在 MySQL 中编写代码将字符转换为十进制。

标签: r decimal numeric rounding-error


【解决方案1】:

您可以创建自己的:

d <- structure( list(i=589L,exp=2L), class="decimal" )
print.decimal <- function( x, ...) print( x$i * 10^(-x$exp) )
> d
[1] 5.89

实际上,一些大数字包也可能适用于此,因为它们使用类似的表示......

【讨论】:

  • 然后你只需要为基本算术运算和你需要的非基本运算编写方法......(但是,很好的答案)
  • @Henrik 我同意。这肯定是一种痛苦。对于您的特定应用程序,精确的回报最好是值得的:-)
【解决方案2】:

Ari 答案的类似方法,但使用 bit64 包中的 integer64 类。使用 big int 作为十进制的底层数据类型是各种原生不支持十进制类型的应用程序中的常见做法。

library(bit64)

as.decimal = function(x, p=2L) structure(as.integer64(x*10^p), class="decimal", precision=p)
print.decimal = function(x) print(as.double(x))
as.integer64.decimal = function(x) structure(x, class="integer64", precision=NULL) # this should not be exported
as.double.decimal = function(x) as.integer64(x)/(10^attr(x, "precision"))
is.decimal = function(x) inherits(x, "decimal")
"==.decimal" = function(e1, e2) `==`(as.integer64(e1), as.integer64(e2))
"+.decimal" = function(e1, e2) `+`(as.integer64(e1), as.integer64(e2))

d = as.decimal(12.69)
is.decimal(d)
#[1] TRUE
print(d)
#[1] 12.69
as.double(d)
#[1] 12.69
d + as.decimal(0.9)
#[1] 13.59
0.1 + 0.2 == 0.3
#[1] FALSE
as.decimal(0.1) + as.decimal(0.2) == as.decimal(0.3)
#[1] TRUE

【讨论】:

    猜你喜欢
    • 2011-09-19
    • 2011-12-23
    • 1970-01-01
    • 2014-12-24
    • 2021-01-31
    • 2014-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多