一种判断两个浮点数是否近似相等的正确方法。
此功能在Swift Numbers 飞行学校指南的第 3 章中讨论。
将 FloatingPointApproximation 包添加到 Package.swift
文件中的目标依赖项。
import PackageDescription
let package = Package(
name: "YourProject",
dependencies: [
.package(
url: "https://github.com/Flight-School/FloatingPointApproximation",
from: "1.0.0"
),
]
)
然后运行 swift build
命令来构建您的项目。
要使用 Carthage 在 Xcode 项目中使用 FloatingPointApproximation
,请在 Cartfile
中指定它。
github "Flight-School/FloatingPointApproximation" ~> 1.0.0
然后运行 carthage update
命令来构建框架,并将构建的 FloatingPointApproximation.framework 拖到您的 Xcode 项目中。
浮点运算可能会产生意想不到的结果,例如 0.1 + 0.2 != 0.3
。 原因是许多小数,包括 0.1
、0.2
和 0.3
,无法用二进制数表示法精确表示。
一个常见的错误是使用一个任意小的常量(例如 .ulpOfOne
)来确定两个浮点数是否近似相等。 例如:
let actual = 0.1 + 0.2
let expected = 0.3
abs(expected - actual) < .ulpOfOne // true
但是,这不适用于大数值:
let actual = 1e25 + 2e25
let expected = 3e25
abs(expected - actual) < .ulpOfOne // false
判断近似相等更好的方法是计算两个浮点数之间存在多少个可表示的值,或者ULPs。
此包定义的 ==~
运算符(及其补码 !=~
)返回一个布尔值,指示两个浮点数是否近似相等。
import FloatingPointApproximation
0.1 + 0.2 == 0.3 // false
0.1 + 0.2 ==~ 0.3 // true
如果两个浮点数在一个最小精度单位(ULP)内,则定义为近似相等。
由于 Swift 实现浮点数的方式,==~
运算符的实现非常简单:
func ==~<T> (lhs: T, rhs: T) -> Bool where T: FloatingPoint {
return lhs == rhs || lhs.nextDown == rhs || lhs.nextUp == rhs
}
一种更完整的方法结合了绝对和相对比较。 isApproximatelyEqual(to:within:maximumULPs:)
方法通过首先检查它是否在给定的绝对裕度内(如果提供),然后检查它是否落在给定的 ULP 数量内,来确定浮点数是否近似等于另一个值。
import FloatingPointApproximation
(0.1 + 0.2).isApproximatelyEqual(to: 0.3, within: 1e-12, maximumULPs: 2)
最终,您有责任根据您所在领域的要求,确定如何比较两个浮点数以实现近似相等。
MIT
Mattt (@mattt)