2015-06-23 18 views
8

Tôi muốn tạo một hàm trả về đạo hàm của một hàm tại một điểm cho một phần của ứng dụng của tôi. Tôi hoàn toàn bị mất về cách tôi sẽ làm điều này ở tất cả. Rõ ràng đây là định nghĩa chính thức về giới hạn. Nhưng loại chức năng nào có thể trả về đạo hàm của một hàm tại một điểm?Chức năng phái sinh nhanh chóng?

enter image description here

Tôi hoàn toàn bị mất. Tôi thực sự không quan tâm những gì người dùng phải nhập lâu như tôi có thể tính đạo hàm tại một điểm nhất định. Bất kỳ ý tưởng?

+3

Bước 1: Tìm một cách để đại diện cho chức năng gốc trong mã. Bước 2: Đảm bảo bạn biết tất cả các quy tắc tính toán cần thiết để lấy đạo hàm của * bất kỳ * chức năng nào. Bước 3: Nếu bạn nhận được bước 1 và bước 2 xuống và bạn vẫn còn bị mắc kẹt ... có lẽ sau đó bạn có thể trở lại Stack Overflow. – nhgrif

+1

Bạn đã thử những gì? Ngoài ra, bạn có thực sự muốn tính đạo hàm thực sự hay chỉ đơn giản là xấp xỉ nó bằng cách sử dụng thuật toán giới hạn đó với một giá trị 'h' rất nhỏ? Cái thứ hai là tầm thường. Cái cũ là không tầm thường. – Rob

+0

Lý tưởng nhất, đạo hàm thực tế sẽ được tính toán. Thuật toán giới hạn sẽ dễ dàng hơn nhiều. – modesitt

Trả lời

10

Dưới đây là cách tiếp cận số đơn giản dựa trên công thức của bạn ở trên. Bạn có thể cải tiến này:

derivativeOf mất một hàm fn và một tọa độ x x và trả về một xấp xỉ bằng số của dẫn xuất của fn tại 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 

Nếu bạn đang có kế hoạch về việc các chức năng từ người dùng, đó là phần khó khăn hơn. Bạn có thể cung cấp cho họ một số mẫu để lựa chọn:

  1. trật tự thứ ba đa thức: y = Ax^3 + Bx^2 + Cx + D
  2. chức năng tội lỗi: y = A * sin(B*x + C)
  3. cos chức năng: y = A * cos(B*x + C)
  4. thứ n root: y = x^(1/N)

, vv Và sau đó bạn có thể yêu cầu họ cung cấp cho bạn A, B, C, D hoặc N

Hãy xem cách thức hoạt động cho đa thức bậc 3:

// 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

Đừng cố gắng và phát minh lại bánh xe. Phân biệt số (phân tích số, nói chung) là một chủ đề lớn (với nhiều giải pháp khả thi * không có giải pháp hoàn hảo) và mọi người thông minh hơn cả bạn và tôi đã đưa ra giải pháp. Trừ khi bạn đang thực sự quan tâm đến tất cả các thuật toán vi phân số khác nhau (thương mại của họ offs, triển khai và tối ưu hóa) tôi sẽ đề nghị đi một tuyến đường. Bạn nói bạn đang sử dụng Swift? Tại sao không chuyển sang Objective-C (Tôi cho rằng bạn đang viết một ứng dụng iOS hoặc OSX). Nếu bạn đã làm, bạn có thể gọi tới số GNU Scientific Library (là thư viện C, C++). Có lẽ bạn có thể gọi mã c/C++ trực tiếp từ Swift? IDK chắc chắn. Nếu bạn thực sự muốn, bạn có thể xem mã của họ và xem cách họ đã triển khai các giải pháp của họ cho sự khác biệt số (mặc dù, tôi sẽ không làm điều đó trừ khi bạn đã sẵn sàng giải quyết một số toán nặng).

implementing the derivative in C/C++ * bạn có thể thử và làm việc với điều này (tôi nghi ngờ điều này là rất mạnh mẽ). Nếu bạn cần chính xác và tốc độ, tôi nghi ngờ bạn muốn làm điều này là trong Swift là tốt.

+1

Swift có thể gọi C và C++;) – Kametrixom

+0

Tôi hoàn toàn có thẩm quyền với môn toán nặng, biết thông qua DifEQ và lý thuyết số ect, nhưng tôi mới tương đối với lập trình hướng đối tượng (bắt đầu cách đây 5 tháng hoặc hơn); front-end web dev trước này). Cảm ơn lời khuyên, tôi sẽ xem xét nó! – modesitt

2

Hàm này lấy hàm làm đối số và trả về hàm dẫn xuất của hàm. h là sự thay đổi nhỏ, trật tự là đối với sự khác biệt. Nó sử dụng đệ quy cho sự khác biệt cao để nó có thể không ổn định.

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

Tôi đồng ý với Collin rằng đây là một chủ đề lớn và có thể không có giải pháp hoàn hảo nào.Tuy nhiên, đối với những người được ok với một giải pháp hiệu quả nhưng không hoàn hảo, câu trả lời của vacawama là đơn giản dễ chịu. Nếu bạn muốn sử dụng hàm dẫn xuất của bạn với một số cú pháp toán học-y nhiều hơn, bạn có thể định nghĩa toán tử, may mắn thay Swift làm cho việc này trở nên dễ dàng đặc biệt. Dưới đây là những gì tôi đã làm:

Lần đầu tiên tôi xác định toán tử để chỉ trả về phiên bản hàm của đạo hàm. Cá nhân tôi thích ký tự for cho các dẫn xuất, nhưng một phần rất lớn các ký tự unicode hiện có là các định danh Swift hợp lệ.

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 
} 

Tiếp theo, cho phép xác định một chức năng mà chúng ta muốn phân biệt:

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

Điều này có thể được sử dụng như vậy: f➚, mà sẽ trả về một một chức năng ẩn danh mà sẽ là đạo hàm của f. Nếu bạn muốn nhận được f tại một điểm cụ thể (ví dụ: x = 2), bạn có thể gọi nó như sau: (f➚)(2)

Tôi đã quyết định sử dụng toán tử, vì vậy tôi đã thực hiện một cú pháp khác tốt hơn một chút:

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

Khái niệm f➚2 bây giờ sẽ trở lại điều tương tự như (f➚)(2) nó chỉ là dễ chịu hơn để sử dụng khi bạn đang làm toán.

Câu hỏi hay, câu trả lời hay, mọi người, tôi chỉ nghĩ rằng tôi sẽ bổ sung thêm điều gì đó. Hãy cho tôi biết nếu bạn có bất kỳ câu hỏi!

5

Phương pháp số có lẽ là tốt nhất cho bạn, nhưng nếu bạn quan tâm đến các phương pháp phân tích, nó rất đơn giản cho các dẫn xuất:

Hãy khai báo những gì một chức năng là (chúng ta giả sử chúng ta có chức năng với một tham số):

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

    func derivative() -> Function 
} 

Bây giờ chúng ta hãy tuyên bố chức năng cơ bản:

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

Việc kê khai của một hàm không phải là rất tốt đẹp:

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

nhưng chúng ta có thể evaluate với đệ quy:

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 
Các vấn đề liên quan