ios - 在 Double 中获得奇怪的值(value)

标签 ios swift floating-point

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

这是我的“攻击”函数,它从僵尸的生命值中移除 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。我想知道为什么会发生这种情况以及如何处理它。

最佳答案

trojanfoe's answer , 他 shares a link描述了有关 float 舍入问题的根源。

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

  1. 您可以转换为整数类型。例如,如果您现有的值都可以用最多两位小数来表示,请将这些值乘以 100,然后在所有地方使用 Int 类型,删除 Double float 代码中的表示。

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

    • 如果在 UI 中显示结果,使用 NumberFormatterDouble 值转换为 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 将使用用户的原生数字格式。

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

  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),因为从小数 Double 创建一个 Decimal 仅捕获 Double 带来的任何不精确性,而上面的三个示例完全避免了这种情况。

关于ios - 在 Double 中获得奇怪的值(value),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32747174/

相关文章:

ios - 使用 map 上的 PINS 时,由于未捕获的异常 'NSInvalidArgumentException' 而终止应用程序

objective-c - 获取 iPhone 上已安装的应用程序列表

swift - ChannelInboundHandler (Swift-NIO) 中的 writeDataUnsupported

arrays - UITableView 中的 UICollectionView - 我想在 CollectionVewCell 中显示数据

SQLite - float 粒度打破唯一约束?

iOS 加载 xib 给出 setValue :forUndefinedKey:]

ios - 为什么 Xcode 在创建类时生成 "unnecessary"代码?

uitableview - Swift - 在自定义 Cell 上使用 autoLayout

零附近的 C++ 浮点比较与 Gtest 失败

assembly - NASM 中的 float 舍入