在Double中获得奇怪的价值

时间:2015-09-23 18:45:18

标签: ios swift floating-point

你好我做了一个" Clicker"作为第一个项目,学习swift我有一个自动计时器,应该从其他数字中删除一些数字,但有时我得到像0.600000000000001的值,我不知道为什么。

这是我的#34;攻击"从僵尸的生命值中移除0.2的函数。

let fGruppenAttackTimer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("fGruppenAttackTime"), userInfo: nil, repeats: true)

func fGruppenAttackTime() {
    zHealth -= 0.2 
    if zHealth <= 0 {
        zHealth = zSize
        pPengar += pPengarut
    }

    ...
}

这是我的attackZ按钮,它应该从僵尸的健康状况中删除1

@IBAction func attackZ(sender: UIButton) {
    zHealth -= Double(pAttack)
    fHunger -= 0.05
    fGruppenHunger.progress = Float(fHunger / 100)
    Actionlbl.text = ""
    if zHealth <= 0 {
        zHealth = zSize
        pPengar += pPengarut
    }
}

最后这里是变量值:

var zHealth = 10.0
var zSize = 10.0
var pAttack = 1
var pPengar = 0
var pPengarut = 1

当计时器打开且功能正在运行时我单击按钮我有时会得到奇怪的值,如0.600000000000001,如果我将函数中的0.2设置为0.25,有时会得到0.0999999999999996。我想知道为什么会发生这种情况以及如何处理它。

2 个答案:

答案 0 :(得分:3)

这是因为浮点舍入错误。

如需进一步阅读,请参阅What Every Computer Scientist Should Know About Floating-Point Arithmetic

  

将无数多个实数压缩成有限数量的位   需要近似的表示。虽然有无限的   许多整数,在大多数程序中,整数计算的结果都可以   以32位存储。相反,给定任意数量的位,   大多数带有实数的计算都会产生数量   不能使用那么多位来精确表示。因此   浮点计算的结果通常必须按顺序舍入   以适应其有限的表示。这个舍入误差是   浮点计算的特征。

答案 1 :(得分:2)

trojanfoe's answer中,他shares a link描述了有关浮点数舍入问题的来源。

就做什么而言,有很多方法:

  1. 您可以切换到整数类型。例如,如果您的现有值都可以用最多两个小数位表示,那么将它们乘以100,然后在任何地方使用Int类型,从您的DoubleFloat表示中删除代码

  2. 您可以简单地处理Double类型引入的非常小的变体。例如:

    • 如果在用户界面中显示结果,请使用NumberFormatter使用指定的小数位数将Double值转换为String

      let formatter = NumberFormatter()
      formatter.maximumFractionDigits = 2
      formatter.minimumFractionDigits = 0  // or you might use `2` here, too
      formatter.numberStyle = .decimal
      
      print(formatter.string(for: value)!)
      

      顺便说一句,NSNumberFormatter也享有另一个好处,即它尊重用户的本地化设置。例如,如果用户位于德国,其中小数位用,而不是.表示,则NSNumberFormatter将使用用户的原生数字格式。

    • 在测试数字是否等于某个值时,而不是仅仅使用==运算符,请查看两个值之间的差异,看看它们是否在某个允许的舍入阈值内。< / p>

  3. 您可以使用Decimal / NSDecimalNumber,在处理小数时不会出现舍入问题:

    var value = Decimal(string: "1.0")!
    value -= Decimal(string: "0.9")!
    value -= Decimal(string: "0.1")!
    

    或者:

    var value = Decimal(1)
    value -= Decimal(sign: .plus, exponent: -1, significand: 9)
    value -= Decimal(sign: .plus, exponent: -1, significand: 1)
    

    或者:

    var value = Decimal(1)
    value -= Decimal(9) / Decimal(10)
    value -= Decimal(1) / Decimal(10)
    

    注意,我明确避免使用任何Double值,例如Decimal(0.1),因为从小数Decimal创建Double只捕获任何不精确Double所需的值,以上三个例子完全避免了这一点。