四舍五入无穷大?
Rounding an Infinite Number?
此问题与较早的 有关,但我收到的是与除以 0 问题无关的无穷大。例如,下面的代码在控制台中打印 4.5300000000000002
,但被标记为 .isInfinate
,因此我无法使用 Codable
进行存储。如何从此示例中得出 4.53(作为双精度数)?
//Calculation
func calculateMaximumAndAverageSkatingEfficiency() {
let heartRateUnit:HKUnit = HKUnit(from: "count/min")
let heartRatesAsDouble = heartRateValues.map { [=10=].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")
}
}
Double
不能精确地存储 4.53 的原因与您不能精确地用十进制写下值 1/3 的原因相同。 (如果您不清楚,请参阅 What Every Programming Should Know About Floating-Point Arithmetic。)
如果您希望舍入为十进制而不是二进制,则需要使用小数类型。参见 Decimal
。
您的 round(to:)
方法不正确,因为它假定 "places" 是 十进制 数字。但是 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 绝不是 "infinite." 它略小于 5。我在您的代码中没有看到它应该生成无限值的任何地方。我会 double-check 你是如何确定的。
此问题与较早的 4.5300000000000002
,但被标记为 .isInfinate
,因此我无法使用 Codable
进行存储。如何从此示例中得出 4.53(作为双精度数)?
//Calculation
func calculateMaximumAndAverageSkatingEfficiency() {
let heartRateUnit:HKUnit = HKUnit(from: "count/min")
let heartRatesAsDouble = heartRateValues.map { [=10=].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")
}
}
Double
不能精确地存储 4.53 的原因与您不能精确地用十进制写下值 1/3 的原因相同。 (如果您不清楚,请参阅 What Every Programming Should Know About Floating-Point Arithmetic。)
如果您希望舍入为十进制而不是二进制,则需要使用小数类型。参见 Decimal
。
您的 round(to:)
方法不正确,因为它假定 "places" 是 十进制 数字。但是 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 绝不是 "infinite." 它略小于 5。我在您的代码中没有看到它应该生成无限值的任何地方。我会 double-check 你是如何确定的。