This question is related to an earlier question however I am receiving an infinite number not related to a divided by 0 problem. For example, the code below prints 4.5300000000000002
in the console but is flagged as .isInfinate
and therefore I cannot store using Codable
. How can I derive 4.53 (as a double) from this example?
//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")
}
}
Double
cannot precisely store 4.53 for the same reason that you cannot precisely write down the value 1/3 in decimal. (See What Every Programming Should Know About Floating-Point Arithmetic if this is unclear to you.)
If you want your rounding to be in decimal rather than binary, then you need to use a decimal type. See Decimal
.
Your round(to:)
method is incorrect because it assumes "places" are decimal digits. But Double
works in binary digits. I believe what you want is this:
extension Double {
func round(toDecimalPlaces places: Int) -> Decimal {
var decimalValue = Decimal(self)
var result = decimalValue
NSDecimalRound(&result, &decimalValue, places, .plain)
return result
}
}
Note that 4.53 is in no way "infinite." It is somewhat less than 5. I don't see anywhere in your code that it should generate an infinite value. I would double-check how you're determining that.