Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift-将英里转换为英尺的测量结果错误_Swift_Measurement - Fatal编程技术网

Swift-将英里转换为英尺的测量结果错误

Swift-将英里转换为英尺的测量结果错误,swift,measurement,Swift,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.co

我一直在使用测量对象来转换大部分长度。但我有一个奇怪的问题。如果我把英里换算成英尺,我几乎能得到正确的答案

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
除了最后一个长英尺的,它们都能工作。在我的游乐场(Xcode版本9.2(9C40b))中,它返回5279.98687664042英尺。我也在常规应用程序构建中进行了测试,得到了相同的结果


你知道发生了什么吗?

你可以看到每个长度单位的定义都有一个名称和一个系数

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

当您进行转换时,
1*1609.34/0.3048
,您得到的是
5279.9868766404197
,而不是预期的
5280
。这只是固定精度浮点运算不精确的结果


如果基本长度单位为1英里,这一点可以得到缓解。这当然是令人难以置信的不受欢迎的,因为世界上大多数国家都不使用这种疯狂的系统,但这是可以做到的。英尺可以定义为系数
5280
,可以用
Double
精确表示。但是现在,不再是英里->英尺不精确,而是米->公里不精确。恐怕不能赢。

< P> >库中定义的“英里”单位不正确,如

所见。
print(UnitLength.miles.converter.baseUnitValue(fromValue: 1.0))
// 1609.34
其中为
1.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
当然,作为, 使用单位进行计算时可能会出现舍入错误,因为测量使用 二进制浮点值作为基础存储。 但这种“明目张胆”的结果是错误的定义
英里单位。

这是一个典型的固定精度浮点精度问题。我已经检查了上面的代码,它运行良好。随着时间的推移,它似乎是固定的。中的定义出人意料地不精确。根据统计,一英里等于1.609344公里有了这个值,1.609344/0.3048计算为5280。嗯,是的,这很重要。我们应该提交一个bug吗?我会认为它是一个bug,其他单位也是(不必要的)不精确的。它是基础的一部分,因此我假设必须在BueGrPr..Apple。我将在苹果公司提交一份缺陷报告。在我的用例中,提供的结果是毫无意义的。我认为类度量应该解释这个问题并提供正确的数字。@JeffKempster请记住,即使
1.609344/0.3048
也不是
5280
,而是
5280000000002
。我想这里真正的不足是
测量
只适用于
双精度
,而不是
Int
十进制
我想知道这是否应该被描述为一个表示问题,而不是一个“舍入误差”。(事实上,现在我仔细观察,这就是亚力山大所说的。)马特:根据维基百科的文章,一英里是25146/15625=1.609344公里,所以在基础中定义为1609.34是错误的(不能用64位双倍的有限精度来解释,这大约是16个十进制数字)。我的意思是,即使有精确的定义,在使用单位进行计算时,也可能会有一些舍入误差。我想我想知道的是,哪里有舍入。对我来说,舍入意味着“让我们随意删除一些有效数字”。这里的要点是,当使用简单的数值表示时,计算精度是有限制的(比如说,与CMTime所做的有理数计算相反)。但是我可能完全错了。@matt:64位IEEE浮点的精度大约是16位十进制数字。所以是的,1.609344不能精确表示。但这并不是使用1.60934的借口。舍入误差本身并不能解释一英里5279.98687664042英尺而不是5280英尺的结果。