Derivadas em Lisp

Esta é uma implementação relativamente simples de derivadas usando Common Lisp. Embora ela não seja tão poderosa como usar um CAS (como o maxima), ela é útil para sabermos o valor da derivada para aquele x. Ela não nos dá, entretanto, a derivada em si, apenas o valor.

Definição

Matematicamente, uma derivada é dada pela expressão:

(1)
\frac{d}{dx} f(x) = \lim_{h\to0} \frac{f(x+h) - f(x)}{h}

O que significa, obviamente, que a derivada nos dá a inclinação da reta tangente à curva descrita por f(x) no ponto x. A idéia aqui não é ensinar derivadas, mas mostrar como elas podem ser implementadas em (Common) Lisp. Antes, só vou dar um exemplo:

(2)
\frac{d}{dx} x^3 = 3x^2
(3)
\frac{d}{dx} 3x^2 = 6x
(4)
\frac{d}{dx} 6x = 6

A partir de (4), as derivadas darão 0. Ou seja, a derivada de 6 é 0, a de 0 é 0, a de 0 é 0, a de 0 é 0…

Implementação

Como não temos uma implementação de limite, usaremos simplesmente um valor “pequeno o suficiente”. Poderíamos usar floating points para representar esse limite, mas eu optei por usar ratios; eles não perdem precisão, mesmo quando fazemos várias derivadas consecutivas.

Esta é a definição de deriv, uma função que retorna a derivada de fn.

(defun deriv (fn)
  (let ((dx 1/1000000000))
    #'(lambda (x)
        (/ (- (funcall fn (+ x dx)) (funcall fn x))
           dx))))

Embora ela retorne a derivada, mesmo que você tente rodar

(print (deriv #'(lambda (x) (* x x))))

você não verá a derivada, mas sim a representação interna da função na sua implementação de Lisp.

Para usá-la, temos três opções: chamar o resultado com funcall, ou atribuir o resultado a um variável e depois chamar essa variável com funcall (o que é praticamente a mesma coisa):

(funcall (deriv #'(lambda (x) (* x x))) 2)
;; ou...
(defvar derivada (deriv #'(lambda (x) (* x x))))
(funcall derivada 2)

ou atribuir, ao invés de usar uma variável comum, usar uma variável que esteja no namespace das funções, o que torna seu uso mais prático:

(setf (symbol-function 'derivada) (deriv #'(lambda (x) (* x x))))
(derivada 2)

Convenhamos que chamar funcall ou atribuir a derivada a uma variável toda vez que quisermos derivar é um estorvo, assim, podemos definir uma outra função, d/dx, que calcula a derivada e já aplica um valor a ela. Outra solução seria definir deriv como um macro, mas isso fica para depois.

(defun d/dx (fn x)
  (funcall (deriv fn) x))

E por fim, podemos definir uma função recursiva que calcula derivadas consecutivas:

(defun dn (n fn x)
  (if (< n 2)
    (d/dx fn x)
    (dn (1- n) (deriv fn) x)))

Só lembrando que na maior parte dos casos nós não teremos o valor exato, mas um valor que se aproxima bastante. E embora no começo eu tenha mostrado as derivadas consecutivas de x^3, nada te impede de usar este código com outros tipos de funções: trigonométricas, exponenciais, logarítmicas, etc.

Page tags: cálculo derivada lisp
page_revision: 4, last_edited: 1239824802|%e %b %Y, %H:%M %Z (%O ago)
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License