Swift - 测量转换(到:)英里到英尺给出了错误的结果

时间:2018-03-19 22:17:01

标签: swift measurement

我一直在使用Measurement对象来转换大部分长度。但我有一个奇怪的问题。如果我从英里转换为英尺,我会得到几乎正确的答案。

import Foundation

let heightFeet = Measurement(value: 6, unit: UnitLength.feet) // 6.0ft
let heightInches = heightFeet.converted(to: UnitLength.inches) // 72.0 in
let heightMeters = heightFeet.converted(to: UnitLength.meters) // 1.8288 m

let lengthMiles = Measurement(value: 1, unit: UnitLength.miles) // 1.0 mi

let lengthFeet = lengthMiles.converted(to: UnitLength.feet) // 5279.98687664042 ft

// Should be 5280.0

他们都工作,除了最后一个lengthFeet。在我的游乐场(Xcode版本9.2(9C40b)),它返回5279.98687664042英尺。我还在常规应用程序构建中测试了相同的结果。

任何想法发生了什么?

2 个答案:

答案 0 :(得分:1)

您可以看到UnitLength here.的定义。每个长度单位都有一个名称和一个系数。

英里单位的系数为1609.34,英尺单位的系数为0.3048。当表示为Double(IEEE 754双精度浮点数)时,最接近的表示分别为1609.33999999999990.30480000000000002

当您执行转化1 * 1609.34 / 0.3048时,您获得5279.9868766404197而不是预期的5280。这只是固定精度浮点数学不精确的结果。

如果长度为一英里的基本单位,则可以减轻。当然,这将是非常不可取的,因为世界上大多数人并没有使用这个疯狂的系统,但它可以做到。脚可以用5280系数定义,可以用Double精确表示。但现在,而不是英里 - >脚不精确,米 - >公里将是不精确的。你不能赢,我害怕。

答案 1 :(得分:1)

“基础”库中的“里程”单位定义不正确,可以通过

查看
print(UnitLength.miles.converter.baseUnitValue(fromValue: 1.0))
// 1609.34

correct value1.609344的位置。 作为基础库中的缺陷的解决方法,您可以定义 你的“更好”里程单位:

extension UnitLength {
    static var preciseMiles: UnitLength {
        return UnitLength(symbol: "mile",
                          converter: UnitConverterLinear(coefficient: 1609.344))
    }
}

并使用它给出了预期的结果:

let lengthMiles = Measurement(value: 1, unit: UnitLength.preciseMiles)
let lengthFeet = lengthMiles.converted(to: UnitLength.feet)
print(lengthFeet) // 5280.0 ft

当然,正如Alexander said, 由于测量使用,在使用单位进行计算时可能会发生舍入误差 二进制浮点值作为底层存储。 但是,这种“公然关闭”结果的原因是错误的定义 英里单位。