在 Swift 中规避精度丢失的妙招
2023-11-09 22:59:56
Swift 中的浮点型以其高效性而著称,但当您深入研究时,可能会遇到一个棘手的陷阱:精度丢失。这就好比用 10 进制表示 1/3——您无论如何也无法得到精确的值。
为什么会出现这种情况呢?让我们从浮点型的底层原理说起。它由两部分组成:一个尾数和一个以 2 为底的指数。然而,可悲的是,2 的倍数无法精确表示十进制小数,例如 0.1 或 0.3。
这就解释了为什么像 0.3 这样的数字在 Swift 中会变成 0.29999999999999999。这不是精度错误,而是二进制表示的固有缺陷。
了解了原因,我们就可以找到规避精度丢失的办法了。以下是一些有效的方法:
-
使用十进制类型: Decimal 类型专为处理十进制小数而设计,精度更高,不会出现舍入误差。
-
舍入操作: 通过舍入或截断操作,您可以控制数字的精度。例如,Decimal 类型提供了一个
rounded()
方法,允许您指定小数点后的位数。 -
保留原始值: 对于需要精确度的情况,最好的办法是保留原始值,而不是对其进行任何浮点运算。这可以防止舍入错误的积累。
-
使用 String 操作: 对于某些场景,您可以使用 String 操作来处理小数。例如,将数字转换为字符串,然后使用
String
类型提供的components(separatedBy:)
方法提取小数部分。
假设我们想计算圆的面积。如果我们使用浮点型,可能会遇到精度丢失:
let radius: Float = 3.14
let area = Float.pi * radius * radius
print(area) // 输出:29.99999821540339
要解决这个问题,我们可以使用 Decimal 类型:
let radius: Decimal = 3.14
let area = Decimal.pi * radius * radius
print(area) // 输出:31.4159265358979323846264338327950288
正如您所看到的,Decimal 类型提供了更高的精度,消除了舍入误差。
在 Swift 中规避精度丢失至关重要,以确保计算的准确性。通过使用适当的数据类型、舍入操作、保留原始值或使用 String 操作,您可以避免令人沮丧的舍入错误,并获得您应得的精确度。