Warm tip: This article is reproduced from stackoverflow.com, please click
math

Derive an exponential value from a for loop's index

发布于 2020-04-09 22:59:12

I have a collection of objects that will animate onto screen. I want the random delay of each animation to progressively grow depending on where the item is in the collection.

At the moment I can do this linearly fairly easily like so (Swift).

let proportionThroughContents = CGFloat(Double(idx) / Double(allNodes.count))
let delayRandomiserBaseValue: CGFloat = 40
let delayRandomiserGrowthValue: CGFloat = 60
let delayRandomiserValue = UInt32(delayRandomiserBaseValue + (delayRandomiserGrowthValue * proportionThroughContents))

I actually want some mathematical function to give me a bit of a hockey-stick like effect, where items in the middle still have low values, but items toward the very end get much higher values.

This may be more a mathematical question rather than a programming one, but I feel like this might be common enough to warrant it being here.

Questioner
Ricky
Viewed
53
Salix alba 2020-02-01 18:48

There are many possible options. The simplest is probably a quadratic like a x^2 + b x + c, where x is your proportion and a, b, c are appropriate constants. In code you would need to write this as a*x*x + b*x + c.

For true exponential functions you want k exp(l x) in code k * Math.exp(l*x).

Choosing the constants is the trickier bit. To get the same initial rates for quadratic just choose b = delayRandomiserGrowthValue and c = delayRandomiserBaseValue. You could then choose the a value depending on how much longer you the delay to be. a + b + c would give you the maximum delay.

let proportionThroughContents = CGFloat(Double(idx) / Double(allNodes.count))
let delayRandomiserBaseValue: CGFloat = 40           // c
let delayRandomiserGrowthValue: CGFloat = 60         // b
let delayRandomiserQuadraticValue: CGFloat = 60      // a
let delayRandomiserValue = UInt32(delayRandomiserBaseValue
       + delayRandomiserGrowthValue * proportionThroughContents 
       + delayRandomiserQuadraticValue * proportionThroughContents * proportionThroughContents  )

For exponential k is the initial value and l*k is initial growth rate. The final delay would be k e^l.

let proportionThroughContents = CGFloat(Double(idx) / Double(allNodes.count))
let delayRandomiserBaseValue: CGFloat = 40           // k
let delayRandomiserGrowthValue: CGFloat = 60         // 
let l: CGFloat = delayRandomiserGrowthValue / delayRandomiserBaseValue  // l
let delayRandomiserValue = UInt32(delayRandomiserBaseValue * Math.exp(l*proportionThroughContents))

With these value l = 60/40 = 1.5 and the maximum delay would be 40*exp(1.5) = 179.