与所有 IEEE 7540 系统一样,Swift 中的数字 like4.7被视为类似的值4.7000000000000002。所以这并不奇怪:
% swift
Welcome to Apple Swift version 5.2.4 (swiftlang-1103.0.32.9 clang-1103.0.32.53).
Type :help for assistance.
1> 4.7
$R0: Double = 4.7000000000000002
2> 4.7 == 4.7000000000000002
$R1: Bool = true
Run Code Online (Sandbox Code Playgroud)
这是一个很好理解的世界现实,因此不需要通过包含指向浮点精度损失背景文章链接的评论来解决。
当使用内置的 编码这个数字时JSONEncoder,我们看到:
4> String(data: JSONEncoder().encode([4.7]), encoding: .utf8)
$R2: String? = "[4.7000000000000002]"
Run Code Online (Sandbox Code Playgroud)
这不是不正确,因为维基百科说这有关JSON和浮点数:
JSON 标准对上溢、下溢、精度损失、舍入或带符号零等实现细节没有要求,但它确实建议期望不超过 IEEE 754 binary64 精度以实现“良好的互操作性”。将浮点数的机器级二进制表示(如 binary64)序列化为人类可读的十进制表示(如 JSON 中的数字)并返回时没有固有的精度损失,因为存在已发布的算法来准确地执行此操作和最佳。
但是,其他 JavaScript 环境倾向于对这些数字进行四舍五入。例如使用 JavaScriptCore:
% /System/Library/Frameworks/JavaScriptCore.framework/Versions/A/Helpers/jsc
>>> 4.7 == 4.7000000000000002
true
>>> JSON.stringify([4.7000000000000002])
[4.7]
Run Code Online (Sandbox Code Playgroud)
并与节点:
% …Run Code Online (Sandbox Code Playgroud) 我需要Decodable正确解码(协议)一个不精确的十进制值,从这个问题我了解如何正确处理十进制实例化,但是在解码时如何做到这一点?
如果尝试将任何数字初始化为字符串
if let value = try! container.decode(String.self, forKey: .d) {
self.taxAmount = Decimal(string: value)
}
Run Code Online (Sandbox Code Playgroud)
我明白了Fatal Error: "Expected to decode String but found a number instead."
如果尝试将 130.43 初始化为十进制
if let value = try! container.decode(Decimal.self, forKey: .d) {
//value.description is 130.43000000000002048
self.d = Decimal(string: value.description)
//making subtotal to be also 130.43000000000002048 and not 130.43
}
Run Code Online (Sandbox Code Playgroud)
解码时有什么方法可以使用这个构造函数吗?
NSDecimalNumber(string: "1.66")NSDecimalNumber(value: 166).dividing(by: 100)Decimal(166)/Decimal(100)Decimal(sign: .plus, exponent: -2, significand: 166)以下是我从外部服务收到的 JSON 的简化版本:
{
"priceAfterTax": 150.00, …Run Code Online (Sandbox Code Playgroud)