Vince O'Sullivan Vince O'Sullivan -4 years ago 132
Swift Question

Swift doubly strange when negative

Xcode 8.2.1, Swift 3.

import UIKit

extension Double {
/// Linear interpolation.
/// Converts a number in one range to its equivalent in another range.
func interpolate(from: ClosedRange<Int>, to: ClosedRange<Int>) -> Double {
let oldValue = self
let offset = Double(to.lowerBound - from.lowerBound)
let expansion = Double(to.upperBound - to.lowerBound) / Double(from.upperBound - from.lowerBound)

print("\nvalue", oldValue)
print("Sign", self.sign)
print("offset", offset)
print("expansion", expansion)
print("oldLowerbound", Double(from.lowerBound))

let newValue = (oldValue - Double(from.lowerBound)) * expansion + offset
return newValue
}
}
print( 1.0.interpolate(from: 0...10, to: 50...70)) // Prints 52.0. Correct
print(-1.0.interpolate(from: 0...10, to: 50...70)) // Prints -52.0. Expected 48.0.
print((-1.0).interpolate(from: 0...10, to: 50...70)) // Prints 48. Correct.


Unit tests pay for themselves when they reveal unexpected problems in the most (seemingly) trivial code:

(The code above will run in an iOS playground.)

Is there a way to extend
Double
in order to get the second print statement to work as expected (without resorting to brackets as in the third print statement)?

Answer Source

It is a matter of evaluation order. Your second expression is evaluated as

-(1.0.interpolate(from: 0...10, to: 50...70)) // -52.0

i.e. interpolate() is called on 1.0, and the result negated.

You have to set explicit parentheses as in your third expression, so that interpolate() is called on -1.0:

(-1.0).interpolate(from: 0...10, to: 50...70) // 48.0.
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download