Skip to content

Instantly share code, notes, and snippets.

@jmcd
Created March 29, 2019 14:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jmcd/ecf188eb6e9d12eae47376fa5210b7bf to your computer and use it in GitHub Desktop.
Save jmcd/ecf188eb6e9d12eae47376fa5210b7bf to your computer and use it in GitHub Desktop.
func positionsOfZeroNetForce(_ magnetPositions: [Double]) -> [Double] {
let threshold = 0.0000000000001
// Utility function to give 1/fn(m0) + 1/fn(m1) + ... + 1/fn(mn)
// Used for working out the force at x, and its derivitive
func sumReciprocals(_ fn: (Double)->(Double)) -> Double {
return magnetPositions.map(fn).map {
guard $0 != 0 else { return Double.nan }
return 1.0/$0
}.reduce(0, +)
}
let pairsOfMagnetPositions = (0..<(magnetPositions.count-1)).map {
(m0: magnetPositions[$0], m1: magnetPositions[$0+1])
}
return pairsOfMagnetPositions.map {
// Newton's method for successively approximating roots of a function
// https://en.wikipedia.org/wiki/Newton%27s_method
var x = $0.0+($0.1-$0.0)/2 // Initial approximation = halfway between positions
var accuracy = threshold*2
repeat {
let forceAtX = sumReciprocals { $0-x }
let derivitiveOfForceAtX = sumReciprocals { ($0-x)*($0-x) }
let xn = x - forceAtX/derivitiveOfForceAtX
accuracy = abs(xn - x)
x = xn
} while threshold < accuracy
return x
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment