比较两个相同的Double值返回false Swift 3

时间:2017-05-11 09:14:37

标签: ios swift

我尝试比较两个相同的纬度,类型为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

任何人都知道发生了什么?

8 个答案:

答案 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)

Swift 4

可能使用舍入的解决方案是获得接近值的最佳选择:

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)

Swift 4.1:

我找到了一个解决方案,对我来说效果很好。这是灵活的原因,因为您可以定义比较的“精度”,方法是传递要考虑的小数位数 Double的扩展。

比如说我们有两个值:

  • value01 = 5.001和
  • value02 = 5.00100004

当仅考虑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!")
}
<块引用>

注意 ~<= 是小于 (<=) 运算符的模糊比较版本,
~>= 是模糊比较大于 (>=) 运算符。