1. 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).

Passo 1

O enunciado pede duas coisas:
  • (a) Implementar a função fatorial de forma iterativa (usando for ou while).
  • (b) Usar essa implementação do fatorial para calcular \pi conforme o exercício 7.3 do Livro (ou seja, implementar um método numérico para aproximar \pi que use fatoriais).
Informações relevantes fornecidas implicitamente:
  • A implementação do fatorial deve ser iterativa (não recursiva).
  • O cálculo de \pi 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 N que controla quantos termos da série usaremos (quanto maior N, 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 n, o fatorial é
n! = 1\cdot 2 \cdot 3 \cdots n,
com a convenção particular 0! = 1.
  • Ideia do algoritmo iterativo: começamos com um acumulador \text{res} = 1. Para cada inteiro k de 2 até n fazemos \text{res} \leftarrow \text{res}\times k. Ao final, \text{res} vale n!.
  • Exemplo numérico passo a passo: calculemos 5!.
    • Inicial: \text{res}=1.
    • k=2: \text{res}=1\times 2=2.
    • k=3: \text{res}=2\times 3=6.
    • k=4: \text{res}=6\times 4=24.
    • k=5: \text{res}=24\times 5=120.
    • Resultado: 5!=120.
  • Observações práticas: tratar n<0 como erro; 0! deve retornar 1. Complexidade em tempo: \mathcal{O}(n). Em memória: \mathcal{O}(1) adicional.

Passo 3

Escolha do método para calcular \pi e mini-aula sobre a série que usaremos:
  • Há várias séries para \pi. 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 \arcsin(x) avaliada em x=1. A série é:
\arcsin(x)=\sum_{n=0}^{\infty}\frac{(2n)!}{4^{n}(n!)^{2}(2n+1)}\,x^{2n+1}.
  • Tomando x=1 obtemos \arcsin(1)=\pi/2, logo
\frac{\pi}{2}=\sum_{n=0}^{\infty}\frac{(2n)!}{4^{n}(n!)^{2}(2n+1)}.
  • Multiplicando por 2:
\pi = 2\sum_{n=0}^{\infty}\frac{(2n)!}{4^{n}(n!)^{2}(2n+1)}.
  • Nesta expressão cada termo usa fatoriais: (2n)! e n!. 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 1/\sqrt{n} (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:
\binom{2n}{n}=\frac{(2n)!}{(n!)^{2}}.
  • Reescrevendo o termo:
\text{termo}_n=\frac{(2n)!}{4^{n}(n!)^{2}(2n+1)}=\frac{\binom{2n}{n}}{4^{n}(2n+1)}.
  • Estratégia: calcular \binom{2n}{n} usando os fatoriais inteiros (nossa função retorna inteiros exatos), depois converter para ponto flutuante ao dividir por 4^{n}(2n+1). 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 n muito grande (2n)! 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 N com bom senso (ex.: algumas centenas no máximo, dependendo do tempo que você tem).

Passo 5

Algoritmo passo a passo para aproximar \pi (implementação mental antes do código):
  • Entrada: número de termos N (um inteiro positivo).
  • Inicialize \text{S}=0 (soma acumulada, em ponto flutuante).
  • Para n variando de 0 até N-1:
    1. Calcule a = (2n)! usando a função fatorial iterativa.
    2. Calcule b = n! usando a mesma função.
    3. Calcule \binom{2n}{n} = a // (b*b) (divisão inteira).
    4. Calcule \text{termo} = \binom{2n}{n} / (4^{n} \cdot (2n+1)) como ponto flutuante.
    5. Atualize \text{S} \leftarrow \text{S} + \text{termo}.
  • Ao final retorne 2\cdot \text{S} como aproximação de \pi.
  • Observação prática: podemos calcular 4^{n} como 4**n ou 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):
    • n=0: \binom{0}{0}=1. \text{termo}_0=1/(1)=1.
    • n=1: \binom{2}{1}=2. \text{termo}_1=2/(4\cdot 3)=2/12\approx 0,1666666667.
    • n=2: \binom{4}{2}=6. \text{termo}_2=6/(16\cdot 5)=6/80=0,075.
    • n=3: \binom{6}{3}=20. \text{termo}_3=20/(64\cdot 7)\approx 0,04464285714.
  • Soma parcial até n=3: S\approx 1 + 0,1666666667 + 0,075 + 0,04464285714 \approx 1,286309524.
  • Aproximação de \pi: 2S\approx 2{,}572619048 (ainda longe de 3{,}14159, 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 N 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 n<0 no fatorial, lance erro/avise.
  • Use aritmética inteira para calcular \binom{2n}{n} exatamente, depois converta para float apenas na divisão final do termo para reduzir erros de arredondamento.
  • Escolha um N adequado para a precisão que você precisa. Por exemplo, para uma aproximação grosseira, N=5 ou N=10 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 N pequeno (por exemplo N=10) e explique como aumentar N 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 n! (inteiro).
  • Função pi_arcsin(N) que usa factorial_iterative para somar os N primeiros termos da série
\pi \approx 2\sum_{n=0}^{N-1}\frac{(2n)!}{4^{n}(n!)^{2}(2n+1)}
e retorna a aproximação de \pi.

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

Exercícios relacionados