Decimal 是 Swift 中用于表示高精度、十进制数值的类型,适用于对精度要求较高的场景,比如财务计算、货币处理、科学运算等。它在底层使用十进制浮点数表示,因此比二进制浮点数(如 Float 或 Double)能更准确地表示和操作十进制数。
Decimal 是 Swift 的类型,但它的实现来源于 Foundation 框架。
主要特点
1、高精度:
使用十进制浮点数存储,避免了二进制浮点数表示十进制数时的舍入误差。
适合货币、财务计算等需要精确小数位的应用场景。
2、支持范围广:
可以表示非常大的或非常小的数字,同时保持高精度。
3、不可变性:
Decimal 本质上是不可变的,每次修改都会返回一个新的实例。
4、与 NSDecimalNumber 的兼容:
Decimal 是 NSDecimalNumber 的 Swift 类型化替代。
创建 Decimal
1、使用直接赋值
可以直接通过十进制浮点数或字符串来创建:
let decimal1: Decimal = 123.456
let decimal2 = Decimal(123.456)
let decimal3 = Decimal(string: "123.456")!
2、使用整数、浮点数创建
let intDecimal = Decimal(123) // 从整数
let doubleDecimal = Decimal(123.45) // 从双精度浮点数
3、使用字符串创建(适合处理更大数值)
if let largeDecimal = Decimal(string: "12345678901234567890.12345") {
print(largeDecimal) // 12345678901234567890.12345
}
基本操作
Decimal 支持常见的算术操作和比较操作,类似于其他数值类型。
1、算术运算
let value1: Decimal = 10.5
let value2: Decimal = 3.2
let sum = value1 + value2 // 加法
let difference = value1 - value2 // 减法
let product = value1 * value2 // 乘法
let quotient = value1 / value2 // 除法
2、比较操作
Decimal 支持常规的比较运算符:
let decimal1: Decimal = 5.0
let decimal2: Decimal = 7.0
print(decimal1 < decimal2) // true
print(decimal1 == decimal2) // false
3、提取值
可以将 Decimal 转换为其他数值类型:
let decimalValue: Decimal = 123.456
let doubleValue = Double(truncating: decimalValue as NSNumber)
let intValue = Int(truncating: decimalValue as NSNumber)
print(doubleValue) // 123.456
print(intValue) // 123
Double(truncating:) 和 Int(truncating:) 是 Swift 中用于将一个支持数值类型的对象(如 NSNumber)转换为目标数值类型的方法。它们主要用于处理跨类型数值转换,尤其是 Foundation 框架中的类型,比如 NSNumber。
精度与舍入
设置小数位数
Decimal 提供了非常灵活的舍入方式和精度控制,通过 NSDecimalRound() 函数可以实现:
var number: Decimal = 123.456789
var roundedNumber = Decimal()
NSDecimalRound(&roundedNumber, &number, 2, .plain) // 四舍五入到小数点后两位
print(roundedNumber) // 输出 123.46
适用场景
1、货币与财务计算:
Decimal 能精确表示和处理货币数值,避免因二进制浮点数导致的舍入误差。
let price: Decimal = 19.99
let quantity: Decimal = 3
let total = price * quantity // 59.97,无精度问题
2、大数值或高精度计算:
可表示非常大的数字或处理需要高精度的小数。
let largeValue = Decimal(string: "12345678901234567890.123456789")!
print(largeValue) // 输出 12345678901234567890.123456789
3、科学计算:
使用高精度的计算场景中,Decimal 能提供更准确的结果。
总结
Decimal 是一个强大的工具,用于处理高精度数值和避免浮点舍入误差,特别是在财务、科学计算等场景下非常有用。它结合了十进制浮点数的准确性和 Swift 的类型安全,为开发者提供了一种灵活而可靠的解决方案。
扩展知识
十进制浮点数与二进制浮点数的区别
1、定义
十进制浮点数:
数值以 10 为基数存储,类似于我们日常使用的十进制数系统。适合处理精确表示十进制小数的场景,如货币和财务计算。
二进制浮点数:
数值以 2 为基数存储,常见于计算机中的 Float 和 Double 类型。更适合科学计算和对精度要求不严格的通用数值运算。
2、精确度
十进制浮点数:
可以精确地表示十进制小数。
比如 0.1 用十进制浮点数表示时可以完全存储为 0.1。
二进制浮点数:
某些十进制小数无法精确表示,存储时会出现舍入误差。
比如 0.1 在二进制浮点数中会存储为一个近似值:0.10000000000000000555…。
3、应用场景
十进制浮点数:
财务计算(例如货币金额)。
精确小数表示(如计量数据、百分比)。
二进制浮点数:
科学计算(对性能需求高,误差容忍度较大)。
大范围数值的快速计算。
4、性能
十进制浮点数:
运算性能通常较低,因为它不是计算机原生的数值表示。
需要更多计算来模拟十进制操作。
二进制浮点数:
由于是计算机硬件原生支持的数值表示,运算性能更高。
Decimal 的范围
Swift 的 Decimal 类型基于 Foundation 框架中的 NSDecimal,使用十进制浮点数实现,其范围和精度如下:
数值范围:
最小值:±1e-38(0.000…0001,有 38 个 0)。
最大值:±1e+38(10 的 38 次方)。
精度:
最大支持 38 位有效数字。
选择十进制还是二进制浮点数
优先使用 Decimal 的场景:
1、财务应用,如货币运算。
2、需要精确表示十进制小数的场景。
3、不希望因二进制误差影响结果的应用。
优先使用 Double 或 Float 的场景:
1、科学计算或高性能需求。
2、对误差容忍度较高的应用。
3、需要表示非常大范围的数值。