Primeira vez aqui? Seja bem vindo e cheque o FAQ!
x

Como posso criar uma classe que implemente a soma entre \(k_0\) e \(k_1\) de uma sequência dada?

0 votos
37 visitas
perguntada Ago 12 em Programação Computacional por Gustavo Libório (16 pontos)  

Esta pergunta corresponde ao exercício 7.12 do livro "A Primer on Scientific Programming with Python", quinta edição; de Langtangen.

Compartilhe

1 Resposta

0 votos
respondida Ago 12 por Gustavo Libório (16 pontos)  
editado Nov 9 por Gustavo Libório
 
Melhor resposta

Vamos primeiro definir nossa classe com o conjunto de métodos especiais necessários. Seguindo o livro, queremos que uma instância seja chamável com um argumento \(x\) de modo tal que possamos, após definir uma regra de sequência \(f\), usar o código como:

def f(k, x):
    return (-x)**k
S = Sum(f, k_0=0, k_1=3)
x = 0.5
print S(x)
print S.f(k=4, x=x) # (-0.5)**4

O exemplo acima foi retirado do livro. Comecemos criando nossa classe e importando o pacote math:

import math    
class Sum:

    def __init__(self, regra, first, last):
         self.func = regra
         self.first = first
         self.last = last

    def __call__(self, x):
         valor = 0
         for k in range(self.first, self.last + 1):
             valor += self.func(x, k)
         return valor

Repare que definimos dois métodos especiais. O primeiro é __init__, que informa como será o procedimento de criar uma instância. Esse método exige dois argumentos: a regra que define cada elemento da sequência e quais são os pontos inicias e finais da soma, ou seja, \(k_0\) e \(k_1\) referidos no enunciado.

O outro método será usado quando uma instância da classe Sum for chamada como se fosse uma função. Ele exige que se informe o valor \(x\) a ser usado na definição da sequência.

Da maneira como está definada, ao chamarmos Sum(x), a classe retorna o valor da soma dos valores da sequência indexados com \(i\) tal que \(k_0 \leq i \geq k_1\), ou seja, retorna:

\[ \sum_{i = k_0}^{k_1} f_i(x) \]

Agora podemos utilizar essa classe para calcular, por exemplo, a soma dos 10 primeiros termos da sequência \( (-x)^{-k} \) com \(k\) natural:

if __name__ == "__main__":
     f = lambda x, k: (-x) ** k
     S = Sum(f, 1, 10)
     print(S(1)) #Output: 0

Nesse caso o valor printado é 0, como esperado!

Agora vamos calcular, como sugere o exercício, a série de Taylor da função seno em torno de 0. Para tanto, recorde-se que podemos escrever que seno, em torno do 0 vale:

\[ sen(x)=\sum_0^\infty \frac{(-1)^n}{(2n+1)!} x^{2n+1}\]

Assim, basta alterar nossa função geradora de termos de modo tal que cada termo da sequência seja o termo correspondente da soma acima. Obtemos:

f_sen = lambda x, k: ((-1) ** k)/fatorial(2*k+1) * x**(2*k+1)

Dessa maneira encerramos com o seguinte código:

if __name__ == "__main__":
    f_sen = lambda x, k: ((-1) ** k)/fatorial(2*k+1) * x**(2*k+1)
    S = Sum(f_sen, 0, 10)
    print(S(math.pi/4))

Ele vai calcular o valor da soma dos 11 primeiros termos da série de Taylor do seno em torno de 0. Como sabemos, podemos aumentar o número de termos até alcançarmos a precisão que quisermos. Veja exemplos da função seno, onde o subscrito representa o número de termos somados:

\[ \begin{align*} sen_0(\frac{\pi}{4}) \approx 0.7853981633974483\\ sen_2(\frac{\pi}{4}) \approx 0.7071430457793603\\ sen_1(\frac{\pi}{4}) \approx 0.7046526512091675\\ sen_{10}(\frac{\pi}{4}) \approx 0.7071067811865475\\ sen_\infty(\frac{\pi}{4}) = \frac{\sqrt 2}{2}\approx 0.70710678118 \\ \end{align*} \]

comentou Nov 5 por VITOR B BORGES (1 ponto)  
editado Nov 5 por VITOR B BORGES
A classe está completamente correta e atende exatamente ao que foi pedido no livro. A solução é bastante elegante e eficiente como método númerico para estimação de constantes como sen(pi/4). Algumas pequenas sugestões para melhorar a replicabilidade do código:

- O enunciado da questão no livro de Langtangen foi escrito na linguagem de programação Python 2, seria interessante fazer as pequenas modificações necessárias para deixar o enunciado replicável em Python 3, que é a linguagem da solução;

- a função fatorial(x) utilizada na definição da expansão de taylor do seno não chegou a ser definida antes da chamada, recomendo colocar ela no mesmo bloco de código.

- No bloco de código em que foi definida f_sen utilizando a palavra-chave 'lambda' foi utilizado o operador '^' para denotar a exponenciação. Não sei se isto é um problema da versão do Python em que eu repliquei o problema porém este operador não serviu para esta operação. Sugiro utilizar o operador '**'.

- Sugiro explicitar a importação do pacote math no código.
comentou Nov 9 por Gustavo Libório (16 pontos)  
Olá Vitor! Suas considerações foram muito importantes. De fato, as alterações sugeridas eram necessárias. Obrigado!
...