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英尺的结果。