基本上问题是在这个例子中:
let d1 = NSNumber(value: 1.4);
let d2 = d1.doubleValue;
let f1 = NSNumber(value: Float(1.4));
let f2 = d1.floatValue;
d1结果1.4
d2结果1.3999999999999999
f1结果1.4
f2结果1.3999999999999998
有谁知道为什么会这样?
我正在尝试解析JSON文件,如:
{"name": "something", "version": 1.4}
使用以下代码:
let json = try (JSONSerialization.jsonObject(with: someData) as? [String: Any])!;
let version: Double = (json["version"] as! NSNumber).doubleValue;
OR
let version: Double = json["version"] as! Double;
OR
let version: Double = json["version"] as! Float;
而我无法获得 1.4 ......
舍入数字对我来说不是一个解决方案,因为我想将这个数字写回JSON文件,这将被解析为其他程序/语言,并且需要精确到1.4在文件中。
有什么建议吗?
更新:问题仅为 1.1
和1.4
。 没有问题 1.2, 1.3, 1.5
更新2:序列化代码:
let jsonDict: Dictionary<String,Any> = [
"name" : name,
"version" : version
];
let data = try? JSONSerialization.data(withJSONObject: jsonDict, options: []);
let jsonString = String(data:data, encoding:.utf8);
答案 0 :(得分:2)
好的,只是为了完成讨论。
最后Decimal
类型做了伎俩。所以我将所有变量引用更改为Decimal
和 NOT NSDecimalNumber
,因为我收到的错误是它不符合Codable
和{{1}协议。也许有一种解决方法,但最简单的解决方案就是坚持使用Decodable
。
我要感谢@JamesBucanek和@EricPostpischil加入讨论并帮助解决这个问题!!!
答案 1 :(得分:0)
我有同样的故事。
我需要使用 API 端点发送/接收浮点值。所以我听从了建议,将 Double
改为 Decimal
。它适用于编码数据,但不适用于解码。
let value = "0.0006"
let decimal = Decimal(string: value)!
print(decimal) // 0.0006 OK
let jsonData = try JSONEncoder().encode(decimal)
print(String(data: jsonData, encoding: .utf8)!) // 0.0006 OK
let decocdedDecimal = try JSONDecoder().decode(Decimal.self, from: jsonData)
print(decocdedDecimal) // 0.0005999999999999998976 NOOOOOO!!!
但是解码到 Double
工作正常。
let decocdedDouble = try JSONDecoder().decode(Double.self, from: jsonData)
print(decocdedDouble) // 0.0006 OK
同样如上面的回答中提到的 - Decimal
应该用 String
初始化以正确编码
let decimal = Decimal(0.0006)
print(decimal) // 0.0005999999999999998976, it will be encoded same way
当然 Double
编码没有按预期工作,否则我们不会遇到这样的问题。
// 0.00059999999999999995 for all cases ofcourse
print(String(data: try JSONEncoder().encode(0.0006), encoding: .utf8)!)
print(String(data: try JSONEncoder().encode(decocdedDouble), encoding: .utf8)!)
print(String(data: try JSONEncoder().encode(Double(value)!), encoding: .utf8)!)
所以我现在的肮脏解决方案是对 Double
值使用包装器。它会将值解码为 Double
,但编码为 Decimal(string:)
struct CodableDouble: Codable {
var value: Double
init(_ value: Double) {
self.value = value
}
init(from decoder: Decoder) throws {
value = try decoder.singleValueContainer().decode(Double.self)
}
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
let decimal = Decimal(string: "\(value)") ?? 0
try container.encode(decimal)
}
}
但我仍然不明白处理这个问题的正确方法是什么。 (除非不使用浮点值)