【问题标题】:Rounding an Infinite Number?四舍五入一个无限数?
【发布时间】:2018-08-03 23:47:29
【问题描述】:

这个问题与较早的question 有关,但是我收到一个与除以 0 问题无关的无限数。例如,下面的代码在控制台中打印4.5300000000000002,但被标记为.isInfinate,因此我无法使用Codable 进行存储。我怎样才能从这个例子中得出 4.53(作为双精度数)?

  //Calculation  
     func calculateMaximumAndAverageSkatingEfficiency() {

            let heartRateUnit:HKUnit = HKUnit(from: "count/min")
            let heartRatesAsDouble = heartRateValues.map { $0.quantity.doubleValue(for: heartRateUnit)}
            let maxHeartRate = heartRatesAsDouble.max()
            guard let maxHeartRateUnwrapped = maxHeartRate else { return }

            maximumEfficiencyFactor = ((1760.0 * (maxSpeed / 60)) / maxHeartRateUnwrapped).round(to: 2)

            guard let averageIceTimeHeartRateUnwrapped = averageIceTimeHeartRate else { return }

            averageEfficiencyFactor = ((1760.0 * (averageSpeed / 60)) / averageIceTimeHeartRateUnwrapped).round(to: 2)

        }

    //Round extension I am using
    extension Double {

        func round(to places: Int) -> Double {
            let divisor = pow(10.0, Double(places))
            return Darwin.round(self * divisor) / divisor
        }

    }

//Usage 
  if let averageEfficiencyFactorUnwrapped = averageEfficiencyFactor {
        if averageEfficiencyFactorUnwrapped.isFinite {
            hockeyTrackerMetadata.averageEfficiencyFactor = averageEfficiencyFactorUnwrapped.round(to: 2)
        } else {
            print("AEF is infinite")
        }

    }

【问题讨论】:

  • 4.5300000000000002 这个数字根本不是无限的。您在打印Double 时得到号码了吗?你用theNumber.isInfinite检查它是无限的吗?
  • 是的,这是在控制台中打印的数字,然后通过 .isInfinite 进行标记
  • minimal reproducible example 会很有帮助。
  • 您发布的代码未提及isInfinite。请发布实际演示问题的代码。您在其他问题中引用的错误消息表明问题出在maximumCapableSpeed,但您的代码也没有提及该属性。
  • 您是否知道,在您发布的代码中,如果averageEfficiencyFactorUnwrapped 是无限的,您会尝试对其进行四舍五入,但如果averageEfficiencyFactorUnwrapped 不是无限,您就错了打印它无限的吗?

标签: ios swift foundation infinite


【解决方案1】:

Double 无法精确存储 4.53,原因与您无法精确记下十进制值 1/3 的原因相同。 (如果您不清楚,请参阅What Every Programming Should Know About Floating-Point Arithmetic。)

如果您希望舍入是十进制而不是二进制,那么您需要使用十进制类型。见Decimal

您的round(to:) 方法不正确,因为它假定“地点”是十进制 位。但是Double 以二进制数字工作。我相信你想要的是这样的:

extension Double {
    func round(toDecimalPlaces places: Int) -> Decimal {
        var decimalValue = Decimal(self)
        var result = decimalValue
        NSDecimalRound(&result, &decimalValue, places, .plain)
        return result
    }
}

请注意,4.53 绝不是“无限的”。它略小于 5。我在您的代码中看不到它应该生成无限值的任何地方。我会仔细检查你是如何确定的。

【讨论】:

  • 我仍然需要一个 Double 但是,let someDouble = Double(someDecimal as NSNumber) 是最好的方法吗?
  • 不可能将 4.53 精确地存储在 Double 中。如果您转换回 Double,您将得到二进制(而不是十进制)四舍五入到接近(但不完全是)4.53 的值。
猜你喜欢
  • 2023-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-12
  • 2011-01-22
  • 1970-01-01
  • 2023-01-12
  • 2020-10-22
相关资源
最近更新 更多