R:序列化base64编码/解码不完全匹配的文本

时间:2010-06-25 15:00:56

标签: r base64 serialization

在我的previous question中使用serialize()来创建对象的CSV我从jmoy得到了一个很好的答案,他推荐了我的序列化文本的base64编码。这正是我想要的。奇怪的是,当我尝试将其付诸实践时,我得到的结果看起来正确,但与我在序列化/编码过程中运行的结果不完全匹配。

下面的示例采用包含3个向量的列表并序列化每个向量。然后,每个向量都是base64编码的,并与密钥一起写入文本文件。关键是矢量的索引号。然后我反转该过程并从csv读回每一行。在最后,您可以看到一些项目完全匹配。这是浮点问题吗?还有别的吗?

require(caTools)

randList <- NULL
set.seed(2)

randList[[1]] <- rnorm(100)
randList[[2]] <- rnorm(200)
randList[[3]] <- rnorm(300)

#delete file contents
fileName <- "/tmp/tmp.txt"
cat("", file=fileName, append=F)

i <- 1
for (item in randList) {
  myLine <- paste(i, ",", base64encode(serialize(item, NULL, ascii=T)), "\n", sep="")
  cat(myLine, file=fileName, append=T) 
  i <- i+1
}

linesIn <- readLines(fileName, n=-1)

parsedThing <- NULL
i <- 1
for (line in linesIn){
  parsedThing[[i]] <- unserialize(base64decode(strsplit(linesIn[[i]], split=",")[[1]][[2]], "raw"))
  i <- i+1
  }

#floating point issue?
identical(randList, parsedThing)

for (i in 1:length(randList[[1]])) {
  print(randList[[1]][[i]] == parsedThing[[1]][[i]])
}

i<-3
randList[[1]][[i]] == parsedThing[[1]][[i]]

randList[[1]][[i]]
parsedThing[[1]][[i]]

这是删节输出:

> #floating point issue?
> identical(randList, parsedThing)
[1] FALSE
> 
> for (i in 1:length(randList[[1]])) {
+   print(randList[[1]][[i]] == parsedThing[[1]][[i]])
+ }
[1] TRUE
[1] TRUE
[1] FALSE
[1] FALSE
[1] TRUE
[1] FALSE
[1] TRUE
[1] TRUE
[1] FALSE
[1] FALSE
...
> 
> i<-3
> randList[[1]][[i]] == parsedThing[[1]][[i]]
[1] FALSE
> 
> randList[[1]][[i]]
[1] 1.587845
> parsedThing[[1]][[i]]
[1] 1.587845
> 

3 个答案:

答案 0 :(得分:2)

JD:我在我的Linux机器上运行了你的代码片段,然后查看了randList [[1]] [[i]] - parsedThing [[1]] [[i]]计算的差异。

是的,值不同,但仅限于我的机器的浮点容差级别。典型的差异是-4.440892e-16--这是非常小的。有些差异为零。

保存/恢复引入(微小)变化水平并不令我感到惊讶。任何重要的数据转换都存在“浮动”最低有效数字的风险。

答案 1 :(得分:2)

好的,现在您显示输出我可以向您解释您正在做什么(遵循Paul在此处的领导)。

由于这是一个已知问题(例如参见此R FAQ entry),您应该扣紧并使用

中的任何一个
  • identical()
  • all.equal()
  • 来自RUnit包的功能,例如checkEquals

总而言之,您正在使用的base64编码似乎没有任何问题。您只是使用了完全的错误定义。但是,嘿,我们是经济学家,无论如何,任何低于一万亿或两万的任何东西都是四舍五入的错误......

答案 2 :(得分:2)

在调用ascii=T时,

serialize会使R在序列化和反序列化时不精确的二进制十进制二进制转换导致值不同。如果你删除ascii=T,你会得到与现在完全相同的数字,这是一个写出的二进制表示。

base64encode可以对原始矢量进行编码,因此不需要ascii=T

serialize使用的二进制表示形式为architecture independent,因此您可以愉快地在一台计算机上进行序列化并在另一台计算机上进行反序列化。

参考:http://cran.r-project.org/doc/manuals/R-ints.html#Serialization-Formats