Ability to JSON serialize and deserialize int64 with precision in R

╄→гoц情女王★ 提交于 2019-12-24 14:12:45

问题


In R, Int64 whole numbers can not be accurately serialized to and from JSON, because existing JSON libraries will coerce the value into a numeric, or expect to represent the number in scientific notation.

Does anyone know of a way to accurately serialize and deserialize whole Int64 numbers to/from JSON with precision, or is a library modification (probably to RJSONIO) required?

The full story, including libraries I have tried so far, and the gacky workarounds necessary for the interim:

> library(gmp)
> library(bit64)
> library(rjson)
> library(RJSONIO)
> 
> options.bak <- getOption("digits")
> options(digits = 22)
> 
> #This is our value! 
> int64.text <- "5812766036735097952"
> #This whole number loses precision when stored as a numeric.
> as.bigz(int64.text) - as.numeric(int64.text)
Big Integer ('bigz') :
[1] 96
> 
> #PROBLEM 1: Deserialization from JSON
> 
> #rjson parses this number as a numeric, and demonstrates the same loss.
> json.text <- "{\"record.id\":5812766036735097952}"
> rjson.parsed <- rjson::fromJSON(json.text)$record.id
> str(rjson.parsed)
 num 5.81e+18
> as.bigz(int64.text) - as.bigz(rjson.parsed)
Big Integer ('bigz') :
[1] 96
> #so does RJSONIO, a library that allows you to specify floating point precision.
> rjsonio.parsed <- RJSONIO::fromJSON(json.text, digits = 50)["record.id"]
> as.bigz(int64.text) - as.bigz(rjsonio.parsed)
Big Integer ('bigz') :
[1] 96
> 
> #For now, I have solved this by hacking the JSON with some regex magic. Here's a snippet, although
> #   i'm really processing a much larger JSON string. 
> modified.json.text <- gsub("record.id\\\":([0-9]+)", "record.id\\\":\"\\1\"", json.text)
> id.text  <- fromJSON(modified.json.text)$record.id
Error in fromJSON(modified.json.text)$record.id : 
  $ operator is invalid for atomic vectors
> id.bigz <- as.bigz(int64.text)
> id.bigz - as.bigz(int64.text)
Big Integer ('bigz') :
[1] 0
> id.bigz
Big Integer ('bigz') :
[1] 5812766036735097952
> 
> #However, hacking the JSON isn't really a good solution, and relies upon there being convenient tags
> # nearby for the regex match to work. Being able to serialize to a precise data structure in the 
> # first place is best. Sorry R, there are largers number than 2^32
> 
> ###Problem 2: Deserialization 
> #Neither rjson and RJSONIO support bigz objects:
> rjson::toJSON(as.bigz(int64.text))
Error in rjson::toJSON(as.bigz(int64.text)) : 
  unable to convert R type 24 to JSON
> RJSONIO::toJSON(as.bigz(int64.text), digits = 50)
Error: evaluation nested too deeply: infinite recursion / options(expressions=)?
Error during wrapup: evaluation nested too deeply: infinite recursion / options(expressions=)?
> #Int64 will serialize, but with scientific notation:
> toJSON(as.integer64(int64.text))
[1] "[ 4.0156e+80 ]"
> RJSONIO::toJSON(as.integer64(int64.text, digits = 50))
[1] "[ 4.0156e+80 ]"
> 
> #So again, another JSON hack is in order:
> encoded.json.out <- toJSON(c(record.id = paste0("INT64", int64.text)))
> modified.json.out <- gsub("record.id\\\":\"INT64([0-9]+)\"", "record.id\\\":\\1", encoded.json.out)
> modified.json.out
[1] "{\n \"record.id\": \"INT645812766036735097952\" \n}"
> options(digits = options.bak)

来源:https://stackoverflow.com/questions/28949729/ability-to-json-serialize-and-deserialize-int64-with-precision-in-r

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!