代码之家  ›  专栏  ›  技术社区  ›  JD Long

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

  •  3
  • JD Long  · 技术社区  · 15 年前

    在我的 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 回复  |  直到 8 年前
        1
  •  2
  •   Jyotirmoy Bhattacharya    15 年前

    ascii=T 在你的电话里 serialize 使R在序列化和非序列化时进行不精确的二进制-十进制-二进制转换,导致值不同。如果你移除 ascii=T 你得到完全相同的数字,因为现在它是一个二进制表示,这是写出来的。

    base64encode 可以对原始向量进行编码,这样就不需要 ascii=T

    所用的二进制表示法 序列化 architecture independent ,因此您可以在一台计算机上愉快地序列化,而在另一台计算机上取消序列化。

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

        2
  •  2
  •   pteetor    15 年前

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

    是的,值是不同的,但只是在我的机器的浮点公差级别。一个典型的差异是-4.440892e-16——这是非常微小的。有些差异是零。

    save/restore引入了这种(微小的)级别的更改,这并不让我感到惊讶。任何有效的数据转换都有可能使最低有效数字“摆动”。

        3
  •  2
  •   Dirk is no longer here    15 年前

    好的,现在你展示了输出,我可以向你解释你在做什么(跟随保罗的领导)。

    因为这是一个已知的问题(参见 R FAQ entry

    • identical()
    • all.equal()
    • 来自 RUnit 包装,如 checkEquals

    总之,您使用的base64编码似乎没有什么问题。你只是用了错误的定义 确切地 . 但是,嘿,我们是经济学家,任何低于1万亿或2万亿的都是舍入误差。。。

    推荐文章