JSON 解析为 Double 数据类型产生不正确的结果
JSON parsing produce incorrect result for Double datatype
我正在尝试将 class 对象转换为 JSON 字符串以显示在屏幕上,但是 Double
数据类型得到了错误的值。
这是我的代码
struct Wallet: Codable {
var balance: Double
var limit: Double
var currency: String
}
func showJSON() {
let data = Wallet(balance: Double(200.24), limit: Double(5000), currency: "INR")
let result = convertToJSONString(data)
print(result!)
}
func convertToJSONString<T: Codable>(_ response: T) -> String? {
var jsonString: String?
let jsonEncoder = JSONEncoder()
jsonEncoder.outputFormatting = .prettyPrinted
if let data = try? jsonEncoder.encode(response) {
jsonString = String(data: data, encoding: .utf8)
}
return jsonString
}
//function call
showJSON()
我的输出是
{
"balance" : 200.24000000000001,
"limit" : 5000,
"currency" : "INR"
}
在这里检查余额值,我们提供了 200.24 但转换后显示为 200.24000000000001。有人可以建议这里需要更改什么以获得准确的输出吗?
Note* - You can copy paste this code to playground directly, it will work without any modifications.
尝试使用 Foundation
中的 Decimal
而不是 Double
。
import Foundation
struct Wallet: Codable {
var balance: Decimal
var limit: Decimal
var currency: String
}
func showJSON() {
let data = Wallet(
balance: Decimal(sign: .plus, exponent: -2, significand: 20024),
limit: 5000,
currency: "INR"
)
let result = convertToJSONString(data)
print(result!)
}
func convertToJSONString<T: Codable>(_ response: T) -> String? {
var jsonString: String?
let jsonEncoder = JSONEncoder()
jsonEncoder.outputFormatting = .prettyPrinted
if let data = try? jsonEncoder.encode(response) {
jsonString = String(data: data, encoding: .utf8)
}
return jsonString
}
//function call
showJSON()
或者,您可能希望使用不同的多精度库。参见 Swift-BigInt, swift-numberkit, or BigInt。但这将需要更多的工作(您可能需要围绕这些制作自己的 Decimal 包装器,或使用 Rational 类型或其他东西)。无论你最终选择什么,如果你真的需要这么高的精度,请确保你有足够的测试来确保某处没有细微的问题。
正如@Devid 上面评论的那样,浮点数并不总是准确的,从 Double
或 Float
到 String
的转换会受到影响。
因此,在转换为 String
的过程中,我们始终可以将 Any
数据类型中的 JSON 保留为 print/show。
基本上,它不会进行转换,因此值不会受到影响。
在这里,我只是替换了上面实现中的 convertToJSONString
函数,如
func convertToJSONString<T: Codable>(_ response: T) -> Any? {
var jsonString: Any?
let jsonEncoder = JSONEncoder()
jsonEncoder.outputFormatting = .prettyPrinted
if let data = try? jsonEncoder.encode(response) {
jsonString = try? JSONSerialization.jsonObject(with: data, options: [])
}
return jsonString
}
使用 JSONSerialization
并获得输出
{
balance = "200.24";
currency = INR;
limit = 5000;
}
用原始 Double
或 Float
值显示大而复杂的 JSON 很有用,要使用它,您始终可以将它们保存在相关数据类型中,这样值就不会得到受影响。
我正在尝试将 class 对象转换为 JSON 字符串以显示在屏幕上,但是 Double
数据类型得到了错误的值。
这是我的代码
struct Wallet: Codable {
var balance: Double
var limit: Double
var currency: String
}
func showJSON() {
let data = Wallet(balance: Double(200.24), limit: Double(5000), currency: "INR")
let result = convertToJSONString(data)
print(result!)
}
func convertToJSONString<T: Codable>(_ response: T) -> String? {
var jsonString: String?
let jsonEncoder = JSONEncoder()
jsonEncoder.outputFormatting = .prettyPrinted
if let data = try? jsonEncoder.encode(response) {
jsonString = String(data: data, encoding: .utf8)
}
return jsonString
}
//function call
showJSON()
我的输出是
{
"balance" : 200.24000000000001,
"limit" : 5000,
"currency" : "INR"
}
在这里检查余额值,我们提供了 200.24 但转换后显示为 200.24000000000001。有人可以建议这里需要更改什么以获得准确的输出吗?
Note* - You can copy paste this code to playground directly, it will work without any modifications.
尝试使用 Foundation
中的 Decimal
而不是 Double
。
import Foundation
struct Wallet: Codable {
var balance: Decimal
var limit: Decimal
var currency: String
}
func showJSON() {
let data = Wallet(
balance: Decimal(sign: .plus, exponent: -2, significand: 20024),
limit: 5000,
currency: "INR"
)
let result = convertToJSONString(data)
print(result!)
}
func convertToJSONString<T: Codable>(_ response: T) -> String? {
var jsonString: String?
let jsonEncoder = JSONEncoder()
jsonEncoder.outputFormatting = .prettyPrinted
if let data = try? jsonEncoder.encode(response) {
jsonString = String(data: data, encoding: .utf8)
}
return jsonString
}
//function call
showJSON()
或者,您可能希望使用不同的多精度库。参见 Swift-BigInt, swift-numberkit, or BigInt。但这将需要更多的工作(您可能需要围绕这些制作自己的 Decimal 包装器,或使用 Rational 类型或其他东西)。无论你最终选择什么,如果你真的需要这么高的精度,请确保你有足够的测试来确保某处没有细微的问题。
正如@Devid 上面评论的那样,浮点数并不总是准确的,从 Double
或 Float
到 String
的转换会受到影响。
因此,在转换为 String
的过程中,我们始终可以将 Any
数据类型中的 JSON 保留为 print/show。
基本上,它不会进行转换,因此值不会受到影响。
在这里,我只是替换了上面实现中的 convertToJSONString
函数,如
func convertToJSONString<T: Codable>(_ response: T) -> Any? {
var jsonString: Any?
let jsonEncoder = JSONEncoder()
jsonEncoder.outputFormatting = .prettyPrinted
if let data = try? jsonEncoder.encode(response) {
jsonString = try? JSONSerialization.jsonObject(with: data, options: [])
}
return jsonString
}
使用 JSONSerialization
并获得输出
{
balance = "200.24";
currency = INR;
limit = 5000;
}
用原始 Double
或 Float
值显示大而复杂的 JSON 很有用,要使用它,您始终可以将它们保存在相关数据类型中,这样值就不会得到受影响。