【问题标题】:How to explain the strange results for while loop with floating point in swift如何在swift中用浮点数解释while循环的奇怪结果
【发布时间】:2017-04-04 05:36:24
【问题描述】:

我测试了下面的while循环,结果不明白。

var x: Float = 0.0
var counter = 0

 while x < 1.41
 {
     x += 0.1
     counter += 1

 }

 print (counter) // 15
 print (x) // 1.5

对于 x

更新: 还有一个。为什么 Double 和 Float 的结果不同?

var x: Double = -0.5
var counter = 0

while x < 1.0
{
    x += 0.1
    counter += 1   
}

print (counter) // 16
print (x)//1.1

var x: Float = -0.5
var counter = 0

while x < 1.0
{
    x += 0.1
    counter += 1   
}

print (counter) // 15
print (x)//1.0

更新 2 和另一个。为什么

var x: Double = 0.0
var counter = 0

while x < 1.5
{
    x += 0.1
    counter += 1
}

print (counter) // 15
print (x) //1.5


var x: Double = 0.0
var counter = 0

while x <= 1.5
{
    x += 0.1
   counter += 1
}

print (counter) // 15
print (x) //1.5

【问题讨论】:

标签: while-loop floating-point swift3


【解决方案1】:

您还能期待什么?循环执行 15 次。第 14 次,x 是 1.4,所以你再加 0.1,得到 1.5。

如果您希望循环在 1.4 终止,您应该在检查 while 条件之前增加 x,而不是之后。

如果您希望循环在 1.41 终止,那么您的增量是错误的,您应该这样做

x += 0.01

改为 141 次迭代。

至于第二个问题,我知道Float 不应该用于货币计算等,因为它缺乏精确性。但是,到目前为止,我信任Double,并且运行 15 中的 while 循环实际上声称 Double 值小于 1.0,而据报道它是 1.0。我们这里有一个精度问题,我们可以看到如果我们从 1.0 中减去 x:

print(1.0-x)

返回:1.11022302462516e-16

同时,Float 似乎在另一个方向上并不精确。在上一次运行中,它比 0.9 (0.9 + 5.96046e-08) 稍大,使其在下一次运行中大于 10。

之所以DoubleFloat在不同的方向上是错误的,只是值的存储方式的问题,根据数量的不同,结果会有所不同。例如,对于 2.0,两个实际值都更大:Double 比 4.440892..e-16 和 Float 比 2.38419e-07。对于 3.0,Double 大 1.33226e-15,Float 小 7.1525e-07。

使用 x.isLess(than: 1.0) 也会出现同样的问题,但是这种方法是 https://developer.apple.com/reference/swift/floatingpoint/1849403-isless 的基础

另一方面,isLessThanOrEqualTo(1.0) 似乎可以按预期可靠地工作。

这个答案现在本身就是一个问题,所以我很好奇是否有人对此有深入的解释......

更新

我想得越多,它就越不是一个 Swift 问题。基本上,您在所有浮点计算中都会遇到这个问题,因为它们从来都不是精确的。 FloatDouble 都不精确,Double 的精确度只有两倍。然而,这意味着像== 这样的比较对于浮点值是没有用的,除非它们都被四舍五入。因此,在具有已知精度(在您的情况下为小数点)的循环中,好的建议是在进行任何类型的比较之前四舍五入到该精度。例如,这将修复循环:

var x: Double = -0.5
var counter = 0

while (round(x * 1000) / 1000) < 1.0
{
    x += 0.1
    counter += 1   
}

print (counter) // 15
print (x)//1.0

var x: Float = -0.5
var counter = 0

while (round(x * 1000) / 1000) < 1.0
{
    x += 0.1
    counter += 1   
}

print (counter) // 15
print (x)//1.0

【讨论】:

猜你喜欢
  • 2017-05-19
  • 1970-01-01
  • 2013-04-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-10
  • 2015-10-09
相关资源
最近更新 更多