- a) Implemente a função fatorial de forma iterativa, usando for ou while.
b) Faça o exercício 7.3 (cálculo de pi) do Livro usando o fatorial implementado no item (a).
b) Faça o exercício 7.3 (cálculo de pi) do Livro usando o fatorial implementado no item (a).
Passo 1
O enunciado pede duas coisas:
- (a) Implementar a função fatorial de forma iterativa (usando
forouwhile). - (b) Usar essa implementação do fatorial para calcular
conforme o exercício 7.3 do Livro (ou seja, implementar um método numérico para aproximar que use fatoriais).
Informações relevantes fornecidas implicitamente:
- A implementação do fatorial deve ser iterativa (não recursiva).
- O cálculo de
deve usar a função fatorial implementada no item (a). - Não foi dada uma precisão ou número de termos, então vamos permitir um parâmetro
que controla quantos termos da série usaremos (quanto maior , melhor a aproximação, em geral).
Passo 2
O que é o fatorial e como fazemos iterativamente (mini-aula):
- Definição: para um inteiro não negativo
, o fatorial é
com a convenção particular
.
- Ideia do algoritmo iterativo: começamos com um acumulador
. Para cada inteiro de até fazemos . Ao final, vale . - Exemplo numérico passo a passo: calculemos
. - Inicial:
. -
: . -
: . -
: . -
: . - Resultado:
.
- Inicial:
- Observações práticas: tratar
como erro; deve retornar . Complexidade em tempo: . Em memória: adicional.
Passo 3
Escolha do método para calcular
e mini-aula sobre a série que usaremos:
- Há várias séries para
. Precisamos de uma que envolva fatoriais para usar a função implementada em (a). Uma escolha padrão e didática é a série de Taylor de avaliada em . A série é:
- Tomando
obtemos , logo
- Multiplicando por 2:
- Nesta expressão cada termo usa fatoriais:
e . Então é perfeita para usar a função do item (a). - Observação sobre convergência: a série converge, mas não extremamente rápida — a taxa de decaimento dos termos é aproximadamente da ordem de
(portanto é relativamente lenta comparada a fórmulas rápidas como as de Ramanujan). Na prática, para obter boa precisão pode ser necessário somar muitos termos.
Passo 4
Transformação prática e estabilidade numérica:
- Para computar cada termo de forma mais estável e evitar divisões desnecessárias, podemos usar o coeficiente binomial central:
- Reescrevendo o termo:
- Estratégia: calcular
usando os fatoriais inteiros (nossa função retorna inteiros exatos), depois converter para ponto flutuante ao dividir por . Isso reduz o número de multiplicações/divisões de ponto flutuante intermediárias e aproveita aritmética inteira exata para binomial. - Atenção: para
muito grande cresce rápido e pode ultrapassar capacidade de inteiros muito grandes ou tornar as divisões imprecisas — em Python inteiro cresce arbitrariamente, mas o custo em tempo aumenta; portanto escolher com bom senso (ex.: algumas centenas no máximo, dependendo do tempo que você tem).
Passo 5
Algoritmo passo a passo para aproximar
(implementação mental antes do código):
- Entrada: número de termos
(um inteiro positivo). - Inicialize
(soma acumulada, em ponto flutuante). - Para
variando de até : - Calcule
usando a função fatorial iterativa. - Calcule
usando a mesma função. - Calcule
(divisão inteira). - Calcule
como ponto flutuante. - Atualize
.
- Calcule
- Ao final retorne
como aproximação de . - Observação prática: podemos calcular
como 4**nou acumulando potência em loop para eficiência.
Passo 6
Exemplo numérico pequeno para fixar a ideia (mostrando como progredimos):
- Vamos calcular os primeiros termos (já mostramos as fórmulas; agora os valores numéricos):
-
: . . -
: . . -
: . . -
: . .
-
- Soma parcial até
: . - Aproximação de
: (ainda longe de , mostrando convergência lenta). - Conclusão: a série funciona e usa fatoriais, mas precisa de muitos termos para alta precisão. Em prova ou tarefa, o importante é mostrar a implementação correta; para obter alta precisão pode-se aumentar
e/ou usar fórmulas mais rápidas.
Passo 7
Cuidados de implementação e sugestões de uso na prova:
- Verifique entradas inválidas: se
no fatorial, lance erro/avise. - Use aritmética inteira para calcular
exatamente, depois converta para float apenas na divisão final do termo para reduzir erros de arredondamento. - Escolha um
adequado para a precisão que você precisa. Por exemplo, para uma aproximação grosseira, ou já dá uma ideia; para obter 6-7 casas provavelmente será necessário muito mais termos. - Se o tempo na prova for curto, indique que você implementaria a soma até um
pequeno (por exemplo ) e explique como aumentar para maior precisão.
Passo 8
Resumo do que implementaremos no código (mínimo necessário pedido pelo enunciado):
- Função iterativa
factorial_iterative(n)que retorna(inteiro). - Função
pi_arcsin(N)que usafactorial_iterativepara somar osprimeiros termos da série
e retorna a aproximação de
.
Resposta
def factorial_iterative(n):
"""
Retorna n! (fatorial de n) de forma iterativa.
Lança ValueError se n for negativo.
"""
if n < 0:
raise ValueError("n must be non-negative")
res = 1
for k in range(2, n + 1):
res *= k
return res
def pi_arcsin(N):
"""
Aproxima pi usando a série de arcsin(1):
pi = 2 * sum_{n=0}^{\infty} ( (2n)! / (4^n (n!)^2 (2n+1)) ).
Aqui somamos os N primeiros termos (n = 0 .. N-1).
"""
if N <= 0:
raise ValueError("N must be a positive integer")
S = 0.0
for n in range(N):
# calcula binomial central de forma exata usando fatoriais inteiros
a = factorial_iterative(2 * n)
b = factorial_iterative(n)
binom = a // (b * b) # inteiro
denom = (4 ** n) * (2 * n + 1)
termo = binom / denom # converte para float na divisão
S += termo
return 2.0 * S
# Exemplos de uso:
if __name__ == "__main__":
for N in [1, 2, 5, 10, 20]:
approx = pi_arcsin(N)
print(f"N={N:2d} -> pi ≈ {approx:.12f}")