Derivative function in swift?
Here is a simple numerical approach based upon your formula above. You could improve upon this:
derivativeOf
takes a function fn
and an x-coordinate x
and returns a numerical approximation of derivative of fn
at x
:
func derivativeOf(fn: (Double)->Double, atX x: Double) -> Double {
let h = 0.0000001
return (fn(x + h) - fn(x))/h
}
func x_squared(x: Double) -> Double {
return x * x
}
// Ideal answer: derivative of x^2 is 2x, so at point 3 the answer is 6
let d1 = derivativeOf(fn: x_squared, atX: 3) // d1 = 6.000000087880153
// Ideal answer: derivative of sin is cos, so at point pi/2 the answer is 0
let d2 = derivativeOf(fn: sin, atX: .pi/2) // d2 = -4.9960036108132044e-08
If you are planning on getting the function from the user, that is the tougher part. You could give them some templates to choose from:
- Third order polynomial:
y = Ax^3 + Bx^2 + Cx + D
- sin function:
y = A * sin(B*x + C)
- cos function:
y = A * cos(B*x + C)
- nth root:
y = x ^ (1/N)
etc. And then you could have them give you A, B, C, D, or N
Let's look at how that would work for a 3rd order polynomial:
// Take coefficients A, B, C, and D and return a function which
// computes f(x) = Ax^3 + Bx^2 + Cx + D
func makeThirdOrderPolynomial(A a: Double, B b: Double, C c: Double, D d: Double) -> ((Double) -> Double) {
return { x in ((a * x + b) * x + c) * x + d }
}
// Get the coefficients from the user
let a = 5.0
let b = 3.0
let c = 1.0
let d = 23.0
// Use the cofficents to make the function
let f4 = makeThirdOrderPolynomial(A: a, B: b, C: c, D: d)
// Compute the derivative of f(x) = 5x^3 + 3x^2 + x + 23 at x = 5
// Ideal answer: derivative is f'(x) = 15x^2 + 6x + 1, f'(5) = 406
let d4 = derivativeOf(fn: f4, atX: 5) // d4 = 406.0000094341376
The numerical approach is probably the best for you but if you are interested in the analytical approach, it's very simple for derivatives:
Let's declare what a function is (we suppose we have functions with one parameter):
protocol Function {
func evaluate(value: Double) -> Double
func derivative() -> Function
}
Now let's declare basic functions:
struct Constant : Function {
let constant: Double
func evaluate(value: Double) -> Double {
return constant
}
func derivative() -> Function {
return Constant(constant: 0)
}
}
struct Parameter : Function {
func evaluate(value: Double) -> Double {
return value
}
func derivative() -> Function {
return Constant(constant: 1)
}
}
struct Negate : Function {
let operand: Function
func evaluate(value: Double) -> Double {
return -operand.evaluate(value)
}
func derivative() -> Function {
return Negate(operand: operand.derivative())
}
}
struct Add : Function {
let operand1: Function
let operand2: Function
func evaluate(value: Double) -> Double {
return operand1.evaluate(value) + operand2.evaluate(value)
}
func derivative() -> Function {
return Add(operand1: operand1.derivative(), operand2: operand2.derivative())
}
}
struct Multiply : Function {
let operand1: Function
let operand2: Function
func evaluate(value: Double) -> Double {
return operand1.evaluate(value) * operand2.evaluate(value)
}
func derivative() -> Function {
// f'(x) * g(x) + f(x) * g'(x)
return Add(
operand1: Multiply(operand1: operand1.derivative(), operand2: operand2),
operand2: Multiply(operand1: operand1, operand2: operand2.derivative())
)
}
}
struct Divide : Function {
let operand1: Function
let operand2: Function
func evaluate(value: Double) -> Double {
return operand1.evaluate(value) / operand2.evaluate(value)
}
func derivative() -> Function {
// (f'(x) * g(x) - f(x) * g'(x)) / (g(x)) ^ 2
return Divide(
operand1: Add(
operand1: Multiply(operand1: operand1.derivative(), operand2: operand2),
operand2: Negate(operand: Multiply(operand1: operand1, operand2: operand2.derivative()))
),
operand2: Power(operand1: operand2, operand2: Constant(constant: 2))
)
}
}
struct Exponential : Function {
let operand: Function
func evaluate(value: Double) -> Double {
return exp(operand.evaluate(value))
}
func derivative() -> Function {
return Multiply(
operand1: Exponential(operand: operand),
operand2: operand.derivative()
)
}
}
struct NaturalLogarithm : Function {
let operand: Function
func evaluate(value: Double) -> Double {
return log(operand.evaluate(value))
}
func derivative() -> Function {
return Multiply(
operand1: Divide(operand1: Constant(constant: 1), operand2: operand),
operand2: operand.derivative()
)
}
}
struct Power : Function {
let operand1: Function
let operand2: Function
func evaluate(value: Double) -> Double {
return pow(operand1.evaluate(value), operand2.evaluate(value))
}
func derivative() -> Function {
// x ^ y = e ^ ln (x ^ y) = e ^ (y * ln x)
let powerFn = Exponential(
operand: Multiply (
operand1: operand2,
operand2: NaturalLogarithm(operand: operand1)
)
)
return powerFn.derivative()
}
}
struct Sin: Function {
let operand: Function
func evaluate(value: Double) -> Double {
return sin(operand.evaluate(value))
}
func derivative() -> Function {
// cos(f(x)) * f'(x)
return Multiply(operand1: Cos(operand: operand), operand2: operand.derivative())
}
}
struct Cos: Function {
let operand: Function
func evaluate(value: Double) -> Double {
return cos(operand.evaluate(value))
}
func derivative() -> Function {
// - sin(f(x)) * f'(x)
return Multiply(operand1: Negate(operand: Sin(operand: operand)), operand2: operand.derivative())
}
}
The declaration of a function is not very nice:
let xSquared = Power(operand1: Parameter(), operand2: Constant(constant: 2))
but we can evaluate
with recursion:
print(xSquared.evaluate(15)) // f(15) = 225
print(xSquared.derivative().evaluate(15)) // f'(15) = 2 * 15 = 30
print(xSquared.derivative().derivative().evaluate(15)) // f''(15) = 2
print(xSquared.derivative().derivative().derivative().evaluate(15)) // f'''(15) = 0