Swift的十进制精度问题

时间:2017-11-16 11:49:34

标签: swift precision nsdecimalnumber

根据文档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结构不准确,还是我误解了什么?

2 个答案:

答案 0 :(得分:5)

NSDecimalNumber(及其叠加类型Decimalcan represent

  

...任何可以表示为mantissa x 10^exponent的数字,其中mantissa是一个长度为38位的十进制整数,exponent是-128到127之间的整数。< / p>

因此可以表示小数分数(最多38位小数) 确切地说,但不是任意数字。特别是1/24 = 0.416666666... 有无限多个十进制数字(repeating decimal),但不能 完全代表Decimal

DecimalNSDecimalNumber之间也没有精确差异。如果我们打印出差异就会变得明显 在实际结果和“理论结果”之间:

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

这是一张证明它的照片:

enter image description here

哦,计算产生0.99999999999999999999999999999999999984而不是1的原因是因为(如Martin R所说)1/24不能完全表示为Decimal