根据文档here,Swift 3/4 Decimal类型是桥接到NSDecimalNumber的基数10中的表示。但是,我在使用NSDecimalNumber时会出现无法重现的精度问题。
let dec24 = Decimal(integerLiteral: 24)
let dec1 = Decimal(integerLiteral: 1)
let decResult = dec1/dec24*dec24
// prints 0.99999999999999999999999999999999999984
let dn24 = NSDecimalNumber(value: 24)
let dn1 = NSDecimalNumber(value: 1)
let dnResult = dn1.dividing(by: dn24).multiplying(by: dn24)
// prints 1
难道Decimal结构不准确,还是我误解了什么?
答案 0 :(得分:5)
NSDecimalNumber
(及其叠加类型Decimal
)can represent
...任何可以表示为
mantissa x 10^exponent
的数字,其中mantissa
是一个长度为38位的十进制整数,exponent
是-128到127之间的整数。< / p>
因此可以表示小数分数(最多38位小数)
确切地说,但不是任意数字。特别是1/24 = 0.416666666...
有无限多个十进制数字(repeating decimal),但不能
完全代表Decimal
。
Decimal
和NSDecimalNumber
之间也没有精确差异。如果我们打印出差异就会变得明显
在实际结果和“理论结果”之间:
let dec24 = Decimal(integerLiteral: 24)
let dec1 = Decimal(integerLiteral: 1)
let decResult = dec1/dec24*dec24
print(decResult - dec1)
// -0.00000000000000000000000000000000000016
let dn24 = NSDecimalNumber(value: 24)
let dn1 = NSDecimalNumber(value: 1)
let dnResult = dn1.dividing(by: dn24).multiplying(by: dn24)
print(dnResult.subtracting(dn1))
// -0.00000000000000000000000000000000000016
答案 1 :(得分:3)
问题只是Playground格式化数字的假象。
我将其输入Playground
import Foundation
let dn1 = Decimal(integerLiteral: 1)
let dn24 = Decimal(integerLiteral: 24)
let decResult = dn1 / dn24 * dn24
print(decResult)
let nsdn1 = NSDecimalNumber(value: 1)
let nsdn24 = NSDecimalNumber(value: 24)
let nsdecResult = nsdn1.dividing(by: nsdn24).multiplying(by: nsdn24)
print(nsdecResult)
Playground在右侧显示第一次计算的0.99999999999999999999999999999999999984
和第二次计算的1
。但是,两个打印报表都打印了0.99999999999999999999999999999999999984
。
这是一张证明它的照片:
哦,计算产生0.99999999999999999999999999999999999984
而不是1
的原因是因为(如Martin R所说)1/24不能完全表示为Decimal
。