我尝试比较两个相同的纬度,类型为Double
,当我打印结果时,它被评估为false
。
print("spot latitude: " + String(spot.location.latitude))
print("first object: " + String(firstSpot.location.latitude))
print(spot.location.latitude == firstSpot.location.latitude)
输出:
spot latitude: 32.8842183049047
first object: 32.8842183049047
false
任何人都知道发生了什么?
答案 0 :(得分:8)
比较双打中的平等很少给你预期的答案,这是由于双打的存储方式。您可以创建自定义运算符,请记住您应该以一定的准确度工作
要了解更多信息,您可以查看answer,即使它说的是ObjC,原则也是超级有效的
由于我在线检查时遇到同样的问题,我在apple dev论坛上找到了这个answer。
这个功能应该可以解决问题,您可以轻松创建自定义运算符:
func doubleEqual(_ a: Double, _ b: Double) -> Bool {
return fabs(a - b) < Double.ulpOfOne
}
我试图将swift 2.x转换为3.x,似乎宏DBL_EPSILON
不再可用了。
答案 1 :(得分:7)
使用==比较double或float值将不会在大多数编程语言中给出预期结果,这意味着您认为应该相等的数字实际上略有不同。相反,如果差值低于某个阈值,则计算绝对差值并将数字处理为相等。有关详细说明,请参阅Compare double to zero using epsilon。
答案 2 :(得分:3)
我认为因为你的两个双号实际上是不同的。 将十进制数转换为字符串时,由于浮点表示,无法避免舍入。即使两个字符串看起来相同,实际数字也可能不同。有关详细信息,请参阅this。
您可以通过指定更多位数来进一步检查两个数字:
print(String(format: "%.20f", double_number))
答案 3 :(得分:3)
可能使用舍入的解决方案是获得接近值的最佳选择:
extension Double {
func precised(_ value: Int = 1) -> Double {
let offset = pow(10, Double(value))
return (self * offset).rounded() / offset
}
static func equal(_ lhs: Double, _ rhs: Double, precise value: Int? = nil) -> Bool {
guard let value = value else {
return lhs == rhs
}
return lhs.precised(value) == rhs.precised(value)
}
}
// values retrieving
a: 64.3465535142464, b: 64.3465535142464
// values debug description
a: 64.346553514246409, b: 64.346553514246395
// calculations
a == b // false
a.precised(10) == b.precised(10) // true
// or
Double.equal(a, b) // false
Double.equal(a, b, precise: 10) // true
如果对epsilon使用修正案,无论如何我得到与双打相等的错误:
// values retrieving
a: 64.3465535142464, b: 64.3465535142464
// values debug description
a: 64.346553514246409, b: 64.346553514246395
// calculations
a == b // false
a - b // 1.4210854715202e-14
a - b < .ulpOfOne // false
答案 4 :(得分:1)
我找到了一个解决方案,对我来说效果很好。这是灵活的原因,因为您可以定义比较的“精度”,方法是传递要考虑的小数位数 Double的扩展。
比如说我们有两个值:
当仅考虑3个小数位时,这些值被视为“相等”,但对于8个小数位,则被视为“不相等”。
extension Double {
/// Compares the receiver (Double) with annother Double considering a defined
/// number of fractional digits.
func checkIsEqual(toDouble pDouble : Double, includingNumberOfFractionalDigits : Int) -> Bool {
let denominator : Double = pow(10.0, Double(includingNumberOfFractionalDigits))
let maximumDifference : Double = 1.0 / denominator
let realDifference : Double = fabs(self - pDouble)
if realDifference >= maximumDifference {
return false
} else {
return true
}
}
}
答案 5 :(得分:1)
您可以使用此扩展名
extension FloatingPoint {
func isNearlyEqual(to value: Self) -> Bool {
return abs(self - value) <= .ulpOfOne
}
}
或根据this guide
extension FloatingPoint {
func isNearlyEqual(to value: Self) -> Bool {
let absA = abs(self)
let absB = abs(value);
let diff = abs(self - value);
if self == value { // shortcut, handles infinities
return true
} else if self == .zero || value == .zero || (absA + absB) < Self.leastNormalMagnitude {
// a or b is zero or both are extremely close to it
// relative error is less meaningful here
return diff < Self.ulpOfOne * Self.leastNormalMagnitude
} else { // use relative error
return diff / min((absA + absB), Self.greatestFiniteMagnitude) < .ulpOfOne;
}
}
}
答案 6 :(得分:0)
我从https://developer.apple.com/documentation/swift/double/1848830-isequal找到了一个不错的解决方案 例如:
let x = 15.0
x.isEqual(to: 15.0)
// true
x.isEqual(to: .nan)
// false
Double.nan.isEqual(to: .nan)
// false
对我有很大帮助,并节省了时间。希望这对其他人也有帮助。 :-)
答案 7 :(得分:0)
将不同的 Swift 4
答案合并在一起:
import Foundation
infix operator ~==
infix operator ~<=
infix operator ~>=
extension Double {
static func ~== (lhs: Double, rhs: Double) -> Bool {
fabs(lhs - rhs) < Double.ulpOfOne
}
static func ~<= (lhs: Double, rhs: Double) -> Bool {
(lhs < rhs) || (lhs ~== rhs)
}
static func ~>= (lhs: Double, rhs: Double) -> Bool {
(lhs > rhs) || (lhs ~== rhs)
}
}
// Check if two double variables are almost equal:
if a ~== b {
print("was nearly equal!")
}
<块引用>
注意 ~<=
是小于 (<=
) 运算符的模糊比较版本,
而 ~>=
是模糊比较大于 (>=
) 运算符。