Reputation: 551
I am trying to calculate the value at any point using an interpolation between the nearest two points in a list. Is there a better / easier way to do this in Swift?
func CalculateDelta( ratio: Double) -> Double {
let ratioArray = [ 1.0, 1.05, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 500 ]
let deltaArray = [ 0.15, 0.15, 0.103, 0.072, 0.053, 0.04, 0.03, 0.023, 0.017, 0.011, 0.006, 0.001, 0 ]
var delta = deltaArray[0]
if (ratio > ratioArray[ratioArray.count - 1] ) {
delta = deltaArray[deltaArray.count - 1]
} else {
for var i=0; i<ratioArray.count-1; i++ {
if (ratio > deltaArray[i]) {
delta = deltaArray[i] + (((ratio - ratioArray[i])/(ratioArray[i+1] - ratioArray[i])) * (deltaArray[i+1] - deltaArray[i]));
break;
}
}
}
return delta
}
Upvotes: 2
Views: 1742
Reputation: 33967
If your code does what you want, then the following is more efficient:
func CalculateDelta(ratio: Double) -> Double {
var result: Double = 0
if ratio <= 500 {
result = 0.15
}
return result
}
But I suspect your code is supposed to be doing something else. I suspect that the below code is more likely correct:
// returns the index of the first element that satisfies the predicate
func find<Seq: SequenceType>(seq: Seq, pred: (Seq.Generator.Element) -> Bool) -> Int? {
for (index, obj) in enumerate(seq) {
if pred(obj) {
return index
}
}
return nil
}
// returns the linear interpolation between two values
func lerp(start: Double, end: Double, percent: Double) -> Double {
return start + percent * (end - start)
}
// returns the percent of value between start and end
func percent(start: Double, end: Double, value: Double) -> Double {
assert(start <= value && value <= end)
return (value - start) / (end - start)
}
func calculateDelta(ratio: Double) -> Double {
let ratioArray = [1.0, 1.05, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 500]
let deltaArray = [0.15, 0.15, 0.103, 0.072, 0.053, 0.04, 0.03, 0.023, 0.017, 0.011, 0.006, 0.001, 0]
// if ratio is below range, return bottom of delta
if ratio < ratioArray[0] {
return deltaArray[0]
}
if let index = find(ratioArray, { ratio <= $0 }) {
if ratioArray[index] == ratio {
// if ratio is equal to element of range, return delta of same index
return deltaArray[index]
}
else {
// figure lerp between too low index and too high index
let p = percent(ratioArray[index - 1], ratioArray[index], ratio)
return lerp(deltaArray[index - 1], deltaArray[index], p)
}
}
// if ratio is above range, return top of delta (0.0)
return 0.0
}
Upvotes: 1