2015-06-23 13 views
8

Volevo creare una funzione che restituisse la derivata di una funzione in un punto per una parte della mia app. Sono assolutamente perso su come lo farei affatto. Ovviamente questa è la definizione formale di un limite. Ma quale tipo di funzione sarebbe in grado di restituire la derivata di una funzione in un punto?Funzione derivativa in rapido?

enter image description here

Io sono totalmente perso. Non mi interessa davvero cosa l'utente debba inserire a lungo, dato che posso calcolare la derivata a un certo punto. Qualche idea?

+3

Fase 1: Trovare un modo per rappresentare la funzione originale nel codice. Passo 2: assicurati di conoscere tutte le regole di calcolo necessarie per prendere la derivata di * qualsiasi * funzione. Passaggio 3: Se si ottiene il passaggio 1 e il passaggio 2 verso il basso e si è ancora bloccati ... forse si potrebbe tornare a Stack Overflow. – nhgrif

+1

Cosa hai provato? Inoltre, vuoi veramente calcolare la derivata effettiva o semplicemente approssimarla usando quell'algoritmo limite con un valore molto piccolo di 'h'? Quest'ultimo è banale. Il primo è non banale. – Rob

+0

Idealmente, la derivata effettiva sarebbe calcolata. L'algoritmo limite sarebbe molto più semplice. – modesitt

risposta

10

Ecco un semplice approccio numerico basato sulla formula sopra riportata. Si potrebbe migliorare su questo:

derivativeOf prende una funzione fn e un x-coordinata x e restituisce un'approssimazione numerica di derivato di fn a 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: M_PI/2) // d2 = -4.996003610813204e-08 

Se si prevede di ottenere la funzione dalla utente, questa è la parte più difficile. Si potrebbe dare loro alcuni modelli tra cui scegliere:

  1. ordine Terzo polinomiale: y = Ax^3 + Bx^2 + Cx + D
  2. funzione sin: y = A * sin(B*x + C)
  3. cos funzione: y = A * cos(B*x + C)
  4. radice ennesima: y = x^(1/N)

etc. E poi potresti farti dare A, B, C, D o N

Diamo un'occhiata a come dovrebbe funzionare per un polinomio di 3 ° ordine:

// 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.0000082972692 
1

Non provare a reinventare la ruota. La differenziazione numerica (analisi numerica, in generale) è un argomento enorme (con molte possibili soluzioni * non ce n'è una perfetta) e le persone molto più intelligenti di te e io abbiamo già trovato soluzioni. A meno che tu non sia realmente interessato a tutti i diversi algoritmi differenziali numerici (le loro compensazioni, implementazioni e ottimizzazioni) suggerirei di intraprendere un'altra strada. Hai detto che stai usando Swift? Perché non passare a Objective-C (presumo che tu stia scrivendo un'app iOS o OSX). Se lo hai fatto, puoi chiamare lo GNU Scientific Library (che è una libreria C, C++). Forse puoi chiamare il codice c/C++ direttamente da Swift? IDK di sicuro.

Se davvero volevi, puoi guardare il loro codice e vedere come hanno implementato le loro soluzioni per la differenziazione numerica (anche se non lo farei se non sei pronto ad affrontare una matematica pesante).

implementing the derivative in C/C++ * si potrebbe provare e lavorare con questo (dubito che questo è molto robusto però). Se hai bisogno di precisione e velocità, dubito che vorresti farlo anche in Swift.

+1

Swift può chiamare C e C++;) – Kametrixom

+0

Sono totalmente competente con la matematica pesante, conoscendo DifEQ e teoria dei numeri ect, ma sono relativamente nuovo alla programmazione orientata agli oggetti (iniziato circa 5 mesi fa; web-end front-end prima di questo). Grazie per il consiglio, lo esaminerò! – modesitt

2

Questa funzione prende una funzione come argomento e restituisce la sua funzione derivata. h è il piccolo turno, l'ordine è rispetto alla differenziazione. Utilizza la ricorsione per la differenziazione di ordine elevato, quindi potrebbe non essere molto stabile.

func differentiate(f:(Double)->(Double),_ h:Double=1e-4,_ order:Int=1)->(Double)->(Double){ 
var k=order 
func diff(x: Double)-> Double{ 
    return (-f(x+2*h)+8*f(x+h)-8*f(x-h)+f(x-2*h))/12/h 
    } 
if(k==0){ 
    return f 
    } 
if(k<0){ 
    fatalError("Order must be non-negative") 
    } 
k=k-1 
if(k>=1){ 
    return differentiate(diff,h*10,k) 
    } 
else{ 
    return diff 
    } 
} 

print(differentiate({(x:Double)->(Double) in sin(x)},0.0001,4)(0)) 
2

Sono d'accordo con Collin sul fatto che questo è un argomento enorme e che probabilmente non esiste una soluzione perfetta.Tuttavia, per quelli che stanno bene con una soluzione efficace ma imperfetta, la risposta di Vacawama è piacevolmente semplice. Se vuoi usare la tua funzione derivativa con qualche altra sintassi matematica, puoi definire un operatore, fortunatamente Swift lo rende eccezionalmente facile. Ecco cosa ho fatto:

Per prima cosa ho definito un operatore per il solo ritorno della versione di funzione della derivata. Personalmente mi piace il carattere for per le derivate, ma una porzione molto grande dei caratteri Unicode esistenti sono identificatori Swift validi.

postfix operator ➚ {} 

postfix func ➚(f: Double -> Double) -> (Double -> Double) { 
    let h = 0.00000000001 
    func de(input: Double) -> Double { 
     return (f(input + h) - f(input))/h 
    } 
    return de 
} 

Avanti, lascia definire una funzione che vogliamo differenziare:

func f(x: Double) -> Double { 
    return x*x + 2*x + 3 
} 

Questo può essere usato come tale: f➚, che restituirà un una funzione anonima che sarà la derivata di f. Se si desidera ottenere f in un punto specifico (ad esempio x = 2), è possibile chiamarlo in questo modo: (f➚)(2)

Ho deciso che mi piacevano gli operatori, quindi ne ho fatto un altro per farmi sembrare quella sintassi un po 'meglio:

infix operator ➚ { associativity left precedence 140 } 
func ➚(left: Double -> Double, right: Double) -> Double { 
    return (f➚)(right) 
} 

l'espressione f➚2 tornerà ora la stessa cosa di (f➚)(2) solo è più piacevole da utilizzare quando si sta facendo la matematica.

Buona domanda, buone risposte a tutti, ho solo pensato di aggiungere qualcosa in più. Fatemi sapere se avete domande!

5

L'approccio numerico è probabilmente la migliore per voi, ma se siete interessati a l'approccio analitico, è molto semplice per i derivati:

Diamo dichiarare ciò che una funzione è (che supponiamo di avere le funzioni con un parametro):

protocol Function { 
    func evaluate(value: Double) -> Double 

    func derivative() -> Function 
} 

Ora cerchiamo di dichiarare funzioni di base:

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()) 
    } 
} 

La dichiarazione di una funzione non è molto bello:

let xSquared = Power(operand1: Parameter(), operand2: Constant(constant: 2)) 

ma possiamo evaluate con ricorsione:

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