{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Capítulos 7-10: Funções, Métodos Numéricos e Projetos Integrados\n",
    "\n",
    "**Disciplina:** FSC1189 - Algoritmo e Programação\n",
    "\n",
    "Exercícios avançados com métodos numéricos e simulações físicas."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "import matplotlib.pyplot as plt\n",
    "from scipy.integrate import odeint\n",
    "from scipy.optimize import fsolve"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Exercício 7.1: Módulo de Funções Físicas\n",
    "\n",
    "**Enunciado:**\n",
    "\n",
    "Crie um módulo com funções para calcular energias em diferentes contextos."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "source": [
    "class FisicaBasica:\n",
    "    \"\"\"Módulo com funções básicas de Física.\"\"\"\n",
    "    \n",
    "    g = 9.81  # aceleração da gravidade (m/s²)\n",
    "    \n",
    "    @staticmethod\n",
    "    def energia_cinetica(massa, velocidade):\n",
    "        \"\"\"\n",
    "        Calcula energia cinética: Ec = (1/2)mv²\n",
    "        \n",
    "        Args:\n",
    "            massa: em kg\n",
    "            velocidade: em m/s\n",
    "        \n",
    "        Returns:\n",
    "            float: energia em joules\n",
    "        \"\"\"\n",
    "        return 0.5 * massa * velocidade**2\n",
    "    \n",
    "    @staticmethod\n",
    "    def energia_potencial(massa, altura, g=9.81):\n",
    "        \"\"\"\n",
    "        Calcula energia potencial gravitacional: Ep = mgh\n",
    "        \n",
    "        Args:\n",
    "            massa: em kg\n",
    "            altura: em metros\n",
    "            g: aceleração da gravidade (padrão 9.81 m/s²)\n",
    "        \n",
    "        Returns:\n",
    "            float: energia em joules\n",
    "        \"\"\"\n",
    "        return massa * g * altura\n",
    "    \n",
    "    @staticmethod\n",
    "    def energia_mecanica(massa, velocidade, altura, g=9.81):\n",
    "        \"\"\"\n",
    "        Calcula energia mecânica total: Em = Ec + Ep\n",
    "        \"\"\"\n",
    "        Ec = FisicaBasica.energia_cinetica(massa, velocidade)\n",
    "        Ep = FisicaBasica.energia_potencial(massa, altura, g)\n",
    "        return Ec + Ep\n",
    "    \n",
    "    @staticmethod\n",
    "    def trabalho(forca, distancia, cosseno_angulo=1):\n",
    "        \"\"\"\n",
    "        Calcula trabalho: W = F·d·cos(θ)\n",
    "        \n",
    "        Args:\n",
    "            forca: força em newtons\n",
    "            distancia: em metros\n",
    "            cosseno_angulo: cos(θ), onde θ é ângulo entre F e d\n",
    "        \n",
    "        Returns:\n",
    "            float: trabalho em joules\n",
    "        \"\"\"\n",
    "        return forca * distancia * cosseno_angulo\n",
    "\n",
    "# Teste\n",
    "m = 5.0  # kg\n",
    "v = 10.0  # m/s\n",
    "h = 2.0  # m\n",
    "\n",
    "Ec = FisicaBasica.energia_cinetica(m, v)\n",
    "Ep = FisicaBasica.energia_potencial(m, h)\n",
    "Em = FisicaBasica.energia_mecanica(m, v, h)\n",
    "\n",
    "print(\"=== ENERGIAS DE UM OBJETO ===\")\n",
    "print(f\"Massa: {m} kg\")\n",
    "print(f\"Velocidade: {v} m/s\")\n",
    "print(f\"Altura: {h} m\")\n",
    "print()\n",
    "print(f\"Energia cinética: {Ec:.2f} J\")\n",
    "print(f\"Energia potencial: {Ep:.2f} J\")\n",
    "print(f\"Energia mecânica: {Em:.2f} J\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "## Exercício 8.1: Método da Bisseção\n",
    "\n",
    "**Enunciado:**\n",
    "\n",
    "Encontre a raiz da função $f(x) = x^3 - 2$ no intervalo [1, 2] usando o método da bisseção."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "source": [
    "def f_exemplo(x):\n",
    "    \"\"\"Função de teste: f(x) = x³ - 2\"\"\"\n",
    "    return x**3 - 2\n",
    "\n",
    "def metodo_bisseccao(f, a, b, tolerancia=1e-6, max_iter=100):\n",
    "    \"\"\"\n",
    "    Encontra raiz usando o método da bisseção.\n",
    "    \n",
    "    Args:\n",
    "        f: função\n",
    "        a, b: intervalo [a, b]\n",
    "        tolerancia: precisão desejada\n",
    "        max_iter: máximo de iterações\n",
    "    \n",
    "    Returns:\n",
    "        tuple: (raiz, iteracoes, erros)\n",
    "    \"\"\"\n",
    "    if f(a) * f(b) >= 0:\n",
    "        raise ValueError(\"f(a) e f(b) devem ter sinais opostos\")\n",
    "    \n",
    "    erros = []\n",
    "    \n",
    "    for i in range(max_iter):\n",
    "        c = (a + b) / 2\n",
    "        fc = f(c)\n",
    "        erro = abs(fc)\n",
    "        erros.append(erro)\n",
    "        \n",
    "        if erro < tolerancia:\n",
    "            return c, i + 1, erros\n",
    "        \n",
    "        if f(a) * fc < 0:\n",
    "            b = c\n",
    "        else:\n",
    "            a = c\n",
    "    \n",
    "    return c, max_iter, erros\n",
    "\n",
    "# Resolver\n",
    "raiz, iteracoes, erros = metodo_bisseccao(f_exemplo, 1, 2)\nraiz_real = 2**(1/3)\n\nprint(\"=== MÉTODO DA BISSEÇÃO ===\")\nprint(f\"Função: f(x) = x³ - 2\")\nprint(f\"Intervalo: [1, 2]\")\nprint()\nprint(f\"Raiz encontrada: {raiz:.10f}\")\nprint(f\"Raiz real: {raiz_real:.10f}\")\nprint(f\"Diferença: {abs(raiz - raiz_real):.2e}\")\nprint(f\"Número de iterações: {iteracoes}\")\nprint(f\"f(raiz) = {f_exemplo(raiz):.2e}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Convergência do Método"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "source": [
    "fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))\n",
    "\n",
    "# Gráfico da função\n",
    "x = np.linspace(0.5, 2.5, 200)\n",
    "y = f_exemplo(x)\n",
    "ax1.plot(x, y, 'b-', linewidth=2, label='f(x) = x³ - 2')\n",
    "ax1.axhline(0, color='k', linestyle='-', linewidth=0.5)\n",
    "ax1.plot(raiz, 0, 'ro', markersize=10, label=f'Raiz = {raiz:.6f}')\n",
    "ax1.set_xlabel('x', fontsize=11)\n",
    "ax1.set_ylabel('f(x)', fontsize=11)\n",
    "ax1.set_title('Função e Raiz Encontrada', fontsize=12, fontweight='bold')\n",
    "ax1.grid(True, alpha=0.3)\n",
    "ax1.legend(fontsize=10)\n",
    "\n",
    "# Convergência dos erros\n",
    "iteracoes_plot = list(range(1, len(erros) + 1))\n",
    "ax2.semilogy(iteracoes_plot, erros, 'g-o', linewidth=2, markersize=4)\n",
    "ax2.set_xlabel('Iteração', fontsize=11)\n",
    "ax2.set_ylabel('|f(c)| (escala log)', fontsize=11)\n",
    "ax2.set_title('Convergência do Método', fontsize=12, fontweight='bold')\n",
    "ax2.grid(True, alpha=0.3, which='both')\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "## Exercício 8.2: Diferenciação Numérica\n",
    "\n",
    "**Enunciado:**\n",
    "\n",
    "Calcule numericamente a derivada de $f(x) = \\sin(x)$ usando diferenças finitas e compare com o resultado analítico (que é $\\cos(x)$)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "source": [
    "def f_sen(x):\n",
    "    return np.sin(x)\n",
    "\n",
    "def f_sen_derivada_real(x):\n",
    "    return np.cos(x)\n",
    "\n",
    "def derivada_numerica_central(f, x, h=1e-5):\n",
    "    \"\"\"\n",
    "    Calcula derivada usando diferença central:\n",
    "    f'(x) ≈ [f(x+h) - f(x-h)] / (2h)\n",
    "    \"\"\"\n",
    "    return (f(x + h) - f(x - h)) / (2 * h)\n",
    "\n",
    "def derivada_numerica_progressiva(f, x, h=1e-5):\n",
    "    \"\"\"\n",
    "    Calcula derivada usando diferença progressiva:\n",
    "    f'(x) ≈ [f(x+h) - f(x)] / h\n",
    "    \"\"\"\n",
    "    return (f(x + h) - f(x)) / h\n",
    "\n",
    "# Teste para x = π/4\n",
    "x_teste = np.pi / 4\n",
    "\n",
    "der_real = f_sen_derivada_real(x_teste)\n",
    "der_central = derivada_numerica_central(f_sen, x_teste)\n",
    "der_progressiva = derivada_numerica_progressiva(f_sen, x_teste)\n",
    "\n",
    "print(\"=== DIFERENCIAÇÃO NUMÉRICA ===\")\nprint(f\"Função: f(x) = sin(x)\")\nprint(f\"Ponto: x = π/4 ≈ {x_teste:.6f}\")\nprint()\nprint(f\"Derivada real (cos(π/4)): {der_real:.10f}\")\nprint(f\"Derivada numérica (diferença central): {der_central:.10f}\")\nprint(f\"Derivada numérica (diferença progressiva): {der_progressiva:.10f}\")\nprint()\nprint(f\"Erro (central): {abs(der_central - der_real):.2e}\")\nprint(f\"Erro (progressiva): {abs(der_progressiva - der_real):.2e}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Análise de Precisão"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "source": [
    "# Variar h e analisar erro\n",
    "h_valores = np.logspace(-8, -2, 50)\n",
    "erros_central = []\n",
    "erros_progressiva = []\n",
    "\n",
    "for h in h_valores:\n",
    "    der_c = derivada_numerica_central(f_sen, x_teste, h)\n",
    "    der_p = derivada_numerica_progressiva(f_sen, x_teste, h)\n",
    "    \n",
    "    erros_central.append(abs(der_c - der_real))\n",
    "    erros_progressiva.append(abs(der_p - der_real))\n",
    "\n",
    "plt.figure(figsize=(10, 6))\n",
    "plt.loglog(h_valores, erros_central, 'b-o', label='Diferença Central', markersize=4)\n",
    "plt.loglog(h_valores, erros_progressiva, 'r-s', label='Diferença Progressiva', markersize=4)\n",
    "plt.xlabel('Tamanho do passo (h)', fontsize=11)\n",
    "plt.ylabel('Erro Absoluto (escala log)', fontsize=11)\n",
    "plt.title('Análise de Precisão - Diferenciação Numérica', fontsize=12, fontweight='bold')\n",
    "plt.legend(fontsize=11)\n",
    "plt.grid(True, alpha=0.3, which='both')\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "## Exercício 8.3: Integração Numérica - Regra do Trapézio\n",
    "\n",
    "**Enunciado:**\n",
    "\n",
    "Calcule a integral $\\int_0^{\\pi} \\sin(x) dx$ usando a regra do trapézio.\n",
    "\n",
    "Valor teórico: $\\int_0^{\\pi} \\sin(x) dx = 2$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "source": [
    "def regra_trapezoidal(f, a, b, n):\n",
    "    \"\"\"\n",
    "    Calcula integral usando regra dos trapézios.\n",
    "    ∫_a^b f(x)dx ≈ (h/2)[f(x₀) + 2f(x₁) + 2f(x₂) + ... + f(xₙ)]\n",
    "    \"\"\"\n",
    "    h = (b - a) / n\n",
    "    x = np.linspace(a, b, n + 1)\n",
    "    y = f(x)\n",
    "    \n",
    "    # Fórmula dos trapézios\n",
    "    integral = h * (y[0] + 2*np.sum(y[1:-1]) + y[-1]) / 2\n",
    "    \n",
    "    return integral, x, y\n",
    "\n",
    "# Calcular para diferentes números de subintervalos\n",
    "a = 0\n",
    "b = np.pi\n",
    "valor_teorico = 2.0\n",
    "\n",
    "n_valores = [10, 50, 100, 500, 1000]\n",
    "\n",
    "print(\"=== INTEGRAÇÃO NUMÉRICA - REGRA DO TRAPÉZIO ===\")\nprint(f\"Integral: ∫₀^π sin(x)dx\")\nprint(f\"Valor teórico: {valor_teorico}\")\nprint()\nprint(\"n     | Valor Aproximado | Erro Absoluto | Erro (%)\")\nprint(\"-\" * 55)\n\nerros = []\nfor n in n_valores:\n    integral, _, _ = regra_trapezoidal(np.sin, a, b, n)\n    erro = abs(integral - valor_teorico)\n    erro_percent = (erro / valor_teorico) * 100\n    \n    erros.append(erro)\n    print(f\"{n:<5} | {integral:16.10f} | {erro:13.2e} | {erro_percent:7.4f}%\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Visualização"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "source": [
    "# Plotar aproximação com n=20\n",
    "n = 20\n",
    "integral, x_trap, y_trap = regra_trapezoidal(np.sin, 0, np.pi, n)\n",
    "\n",
    "fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))\n",
    "\n",
    "# Gráfico da aproximação\n",
    "x_continuo = np.linspace(0, np.pi, 200)\n",
    "y_continuo = np.sin(x_continuo)\n",
    "\n",
    "ax1.plot(x_continuo, y_continuo, 'b-', linewidth=2, label='sin(x)')\n",
    "ax1.fill_between(x_continuo, y_continuo, alpha=0.2, color='blue')\n",
    "ax1.plot(x_trap, y_trap, 'ro-', markersize=5, label=f'Aproximação (n={n})')\n",
    "\n",
    "# Trapézios\n",
    "for i in range(len(x_trap) - 1):\n",
    "    ax1.fill_between([x_trap[i], x_trap[i+1]], \n",
    "                     [y_trap[i], y_trap[i+1]], \n",
    "                     alpha=0.1, color='red')\n",
    "\n",
    "ax1.set_xlabel('x', fontsize=11)\n",
    "ax1.set_ylabel('sin(x)', fontsize=11)\n",
    "ax1.set_title(f'Aproximação com Trapézios (n={n})', fontsize=12, fontweight='bold')\n",
    "ax1.legend(fontsize=10)\n",
    "ax1.grid(True, alpha=0.3)\n",
    "\n",
    "# Convergência do erro\n",
    "ax2.loglog(n_valores, erros, 'go-', linewidth=2, markersize=8)\n",
    "ax2.set_xlabel('Número de subintervalos (n)', fontsize=11)\n",
    "ax2.set_ylabel('Erro Absoluto (escala log)', fontsize=11)\n",
    "ax2.set_title('Convergência da Regra do Trapézio', fontsize=12, fontweight='bold')\n",
    "ax2.grid(True, alpha=0.3, which='both')\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "source": "---\n\n## Exercício 8.4: Integração Numérica - Regra de Simpson\n\n**Enunciado:**\n\nCalcule a integral $\\int_0^{\\pi} \\sin(x) dx$ usando a regra de Simpson (1/3).\n\nA regra de Simpson tem precisão de ordem O(h⁴), melhor que o trapézio O(h²).",
   "metadata": {}
  },
  {
   "cell_type": "markdown",
   "source": "### Visualização e Comparação de Métodos",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "source": "# Gráfico de convergência de erros\nfig, (ax1, ax2) = plt.subplots(1, 2, figsize=(13, 5))\n\n# Recalcular erros para o gráfico\nn_plot = np.array([5, 10, 20, 50, 100, 200, 500, 1000])\nerros_trap_plot = []\nerros_simp_plot = []\n\nfor n in n_plot:\n    integral_trap, _, _ = regra_trapezoidal(np.sin, a, b, n)\n    integral_simp, _, _ = regra_simpson(np.sin, a, b, n)\n    \n    erros_trap_plot.append(abs(integral_trap - valor_teorico))\n    erros_simp_plot.append(abs(integral_simp - valor_teorico))\n\n# Painel 1: Log-log plot\nax1.loglog(n_plot, erros_trap_plot, 'b-o', linewidth=2, markersize=8, label='Trapézio (O(h²))')\nax1.loglog(n_plot, erros_simp_plot, 'r-s', linewidth=2, markersize=8, label='Simpson (O(h⁴))')\n\n# Linhas de referência\nn_ref = np.array([5, 1000])\n# O(h²) ∝ 1/n²\nh = (b - a) / n_ref\nref_h2 = 0.001 / n_ref**2\nax1.loglog(n_ref, ref_h2, 'b--', alpha=0.5, linewidth=1, label='Referência O(1/n²)')\n\n# O(h⁴) ∝ 1/n⁴\nref_h4 = 0.0001 / n_ref**4\nax1.loglog(n_ref, ref_h4, 'r--', alpha=0.5, linewidth=1, label='Referência O(1/n⁴)')\n\nax1.set_xlabel('Número de subintervalos (n)', fontsize=11)\nax1.set_ylabel('Erro Absoluto (escala log)', fontsize=11)\nax1.set_title('Convergência: Comparação Trapézio × Simpson', fontsize=12, fontweight='bold')\nax1.legend(fontsize=10)\nax1.grid(True, alpha=0.3, which='both')\n\n# Painel 2: Visualização das fórmulas\nx_simp = np.linspace(a, b, 9)\ny_simp = np.sin(x_simp)\n\nx_continuo = np.linspace(a, b, 200)\ny_continuo = np.sin(x_continuo)\n\nax2.plot(x_continuo, y_continuo, 'k-', linewidth=2.5, label='sin(x)')\nax2.fill_between(x_continuo, y_continuo, alpha=0.15, color='blue')\n\n# Desenhar parábolas para Simpson (usando polinômios por pares de intervalos)\nfor i in range(0, len(x_simp) - 2, 2):\n    x_parab = np.linspace(x_simp[i], x_simp[i+2], 30)\n    # Interpolação quadrática\n    coeffs = np.polyfit([x_simp[i], x_simp[i+1], x_simp[i+2]], \n                        [y_simp[i], y_simp[i+1], y_simp[i+2]], 2)\n    y_parab = np.polyval(coeffs, x_parab)\n    ax2.fill_between(x_parab, y_parab, alpha=0.2, color='red')\n    ax2.plot(x_parab, y_parab, 'r-', linewidth=1.5)\n\nax2.plot(x_simp, y_simp, 'ro', markersize=8, label='Pontos de avaliação')\nax2.set_xlabel('x', fontsize=11)\nax2.set_ylabel('sin(x)', fontsize=11)\nax2.set_title('Regra de Simpson (n=8): Parábolas vs Função Real', fontsize=12, fontweight='bold')\nax2.legend(fontsize=10)\nax2.grid(True, alpha=0.3)\nax2.set_xlim(a, b)\n\nplt.tight_layout()\nplt.show()",
   "metadata": {},
   "execution_count": null,
   "outputs": []
  },
  {
   "cell_type": "code",
   "source": "def regra_simpson(f, a, b, n):\n    \"\"\"\n    Calcula integral usando regra de Simpson (1/3).\n    \n    Fórmula: ∫_a^b f(x)dx ≈ (h/3)[f(x₀) + 4f(x₁) + 2f(x₂) + 4f(x₃) + ... + f(xₙ)]\n    \n    Nota: n deve ser par para aplicar corretamente\n    \n    Args:\n        f: função a integrar\n        a, b: limites de integração\n        n: número de subintervalos (deve ser par)\n    \n    Returns:\n        integral: valor aproximado da integral\n        x: pontos de avaliação\n        y: valores da função nos pontos\n    \"\"\"\n    if n % 2 != 0:\n        n += 1  # Garantir que n seja par\n    \n    h = (b - a) / n\n    x = np.linspace(a, b, n + 1)\n    y = f(x)\n    \n    # Coeficientes de Simpson\n    coeficientes = np.ones(n + 1)\n    coeficientes[0] = 1\n    coeficientes[-1] = 1\n    coeficientes[1:-1:2] = 4  # índices ímpares\n    coeficientes[2:-1:2] = 2  # índices pares (exceto primeiro e último)\n    \n    integral = (h / 3) * np.sum(coeficientes * y)\n    \n    return integral, x, y\n\n# Calcular para diferentes números de subintervalos\na = 0\nb = np.pi\nvalor_teorico = 2.0\n\nn_valores = [10, 50, 100, 500, 1000]\n\nprint(\"=== INTEGRAÇÃO NUMÉRICA - REGRA DE SIMPSON ===\")\nprint(f\"Integral: ∫₀^π sin(x)dx\")\nprint(f\"Valor teórico: {valor_teorico}\")\nprint()\nprint(\"n     | Valor Aproximado | Erro Absoluto | Erro (%)\")\nprint(\"-\" * 55)\n\nerros_simpson = []\nfor n in n_valores:\n    integral, _, _ = regra_simpson(np.sin, a, b, n)\n    erro = abs(integral - valor_teorico)\n    erro_percent = (erro / valor_teorico) * 100\n    \n    erros_simpson.append(erro)\n    print(f\"{n:<5} | {integral:16.10f} | {erro:13.2e} | {erro_percent:7.4f}%\")\n\n# Comparar com trapézio\nprint(\"\\n=== COMPARAÇÃO: SIMPSON vs TRAPÉZIO ===\")\nprint()\nprint(\"n     | Erro Trapézio | Erro Simpson | Melhoria\")\nprint(\"-\" * 50)\n\nfor i, n in enumerate(n_valores):\n    integral_trap, _, _ = regra_trapezoidal(np.sin, a, b, n)\n    integral_simp, _, _ = regra_simpson(np.sin, a, b, n)\n    \n    erro_trap = abs(integral_trap - valor_teorico)\n    erro_simp = abs(integral_simp - valor_teorico)\n    \n    if erro_trap > 0:\n        melhoria = erro_trap / erro_simp\n    else:\n        melhoria = float('inf')\n    \n    print(f\"{n:<5} | {erro_trap:13.2e} | {erro_simp:12.2e} | {melhoria:7.2f}x\")",
   "metadata": {},
   "execution_count": null,
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "## Exercício 10.1: Projeto - Análise de Dados de Pêndulo Simples\n",
    "\n",
    "**Cenário:**\n",
    "\n",
    "Dados experimentais de período de um pêndulo em função do comprimento.\n",
    "Objetivo: Estimar $g$ a partir da relação $T = 2\\pi\\sqrt{L/g}$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "source": [
    "# Dados experimentais (simulados com ruído)\n",
    "np.random.seed(42)\n",
    "L_teorico = np.array([0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0])  # metros\n",
    "g_real = 9.81  # m/s²\n",
    "\n",
    "# Calcular períodos teóricos\n",
    "T_teorico = 2 * np.pi * np.sqrt(L_teorico / g_real)\n",
    "\n",
    "# Adicionar ruído experimental (1%)\n",
    "ruido = 0.01 * T_teorico * np.random.randn(len(T_teorico))\n",
    "T_medido = T_teorico + ruido\n",
    "\n",
    "# Criar tabela\n",
    "df_pendulo = pd.DataFrame({\n",
    "    'Comprimento L (m)': L_teorico,\n",
    "    'Período T teórico (s)': T_teorico,\n",
    "    'Período T medido (s)': T_medido,\n",
    "    'Erro (%)': (np.abs(T_medido - T_teorico) / T_teorico) * 100\n",
    "})\n",
    "\n",
    "print(\"=== DADOS DE PÊNDULO SIMPLES ===\")\nprint(df_pendulo.to_string(index=False))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Análise de Dados"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "source": [
    "# Usar relação: T² = (4π²/g)L para ajustar uma reta\n",
    "# Se plotar T² vs L, a inclinação = 4π²/g\n",
    "\n",
    "T_squared = T_medido**2\n",
    "\n",
    "# Regressão linear\n",
    "# T² = aL + b, onde a = 4π²/g\n",
    "coef = np.polyfit(L_teorico, T_squared, 1)\n",
    "a = coef[0]\n",
    "b = coef[1]\n",
    "\n",
    "g_estimado = 4 * np.pi**2 / a\n",
    "\n",
    "print(\"\\n=== ANÁLISE DE REGRESSÃO LINEAR ===\")\nprint(f\"Ajuste: T² = {a:.6f}·L + {b:.6f}\")\nprint(f\"Coeficiente angular (a): {a:.6f}\")\nprint(f\"Coeficiente linear (b): {b:.6f}\")\nprint()\nprint(f\"g estimado: {g_estimado:.3f} m/s²\")\nprint(f\"g real: {g_real:.3f} m/s²\")\nprint(f\"Erro: {abs(g_estimado - g_real):.4f} m/s² ({(abs(g_estimado - g_real)/g_real)*100:.2f}%)\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Visualização"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "source": [
    "fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))\n",
    "\n",
    "# Gráfico T vs L\n",
    "ax1.scatter(L_teorico, T_medido, s=80, alpha=0.7, label='Dados medidos', color='blue')\n",
    "ax1.plot(L_teorico, T_teorico, 'r--', linewidth=2, label='Valor teórico')\n",
    "ax1.set_xlabel('Comprimento L (m)', fontsize=11)\n",
    "ax1.set_ylabel('Período T (s)', fontsize=11)\n",
    "ax1.set_title('Período vs Comprimento', fontsize=12, fontweight='bold')\n",
    "ax1.legend(fontsize=10)\n",
    "ax1.grid(True, alpha=0.3)\n",
    "\n",
    "# Gráfico T² vs L (regressão linear)\n",
    "L_fit = np.linspace(L_teorico.min(), L_teorico.max(), 100)\n",
    "T2_fit = a * L_fit + b\n",
    "\n",
    "ax2.scatter(L_teorico, T_squared, s=80, alpha=0.7, label='Dados medidos', color='green')\n",
    "ax2.plot(L_fit, T2_fit, 'b-', linewidth=2, label=f'Ajuste linear')\n",
    "ax2.set_xlabel('Comprimento L (m)', fontsize=11)\n",
    "ax2.set_ylabel('Período² T² (s²)', fontsize=11)\n",
    "ax2.set_title('T² vs L - Regressão Linear', fontsize=12, fontweight='bold')\n",
    "ax2.legend(fontsize=10)\n",
    "ax2.grid(True, alpha=0.3)\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "## Exercício 10.2: Projeto - Simulação de Queda Livre com Arrasto\n",
    "\n",
    "**Cenário:**\n",
    "\n",
    "Simular a queda de um objeto considerando resistência do ar."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "source": [
    "def queda_livre_com_arrasto(condicoes_iniciais, parametros, t_total):\n",
    "    \"\"\"\n",
    "    Simula queda livre com arrasto quadrático.\n",
    "    \n",
    "    dv/dt = g - (b/m)v|v|\n",
    "    \"\"\"\n",
    "    def derivada(y, t, g, b, m):\n",
    "        v = y[0]\n",
    "        aceleracao = g - (b / m) * v * abs(v)\n",
    "        return [aceleracao]\n",
    "    \n",
    "    g = parametros['g']\n",
    "    b = parametros['b']  # coeficiente de arrasto\n",
    "    m = parametros['m']  # massa\n",
    "    \n",
    "    t = np.linspace(0, t_total, 500)\n",
    "    solucao = odeint(derivada, condicoes_iniciais, t, args=(g, b, m))\n",
    "    \n",
    "    return t, solucao[:, 0]\n",
    "\n",
    "# Parâmetros\n",
    "parametros = {\n",
    "    'g': 9.81,      # aceleração da gravidade\n",
    "    'b': 0.1,       # coeficiente de arrasto\n",
    "    'm': 1.0        # massa em kg\n",
    "}\n",
    "\n",
    "# Velocidade terminal\n",
    "v_terminal = np.sqrt(parametros['g'] * parametros['m'] / parametros['b'])\n",
    "\n",
    "# Simular\n",
    "t, v = queda_livre_com_arrasto([0], parametros, 10)\n",
    "\n",
    "# Também simular sem arrasto para comparação\n",
    "parametros_sem_arrasto = parametros.copy()\n",
    "parametros_sem_arrasto['b'] = 0.001  # arrasto negligenciável\n",
    "t2, v_sem_arrasto = queda_livre_com_arrasto([0], parametros_sem_arrasto, 10)\n",
    "\n",
    "print(\"=== SIMULAÇÃO: QUEDA COM ARRASTO ===\")\nprint(f\"Massa: {parametros['m']} kg\")\nprint(f\"Coeficiente de arrasto: {parametros['b']}\")\nprint(f\"Velocidade terminal: {v_terminal:.2f} m/s\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Visualização"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "source": [
    "plt.figure(figsize=(10, 6))\n",
    "\n",
    "plt.plot(t, v, 'b-', linewidth=2, label=f'Com arrasto (b={parametros[\"b\"]})')\n",
    "plt.plot(t2, v_sem_arrasto, 'r--', linewidth=2, label='Sem arrasto')\n",
    "plt.axhline(v_terminal, color='g', linestyle=':', linewidth=2, label=f'Velocidade terminal = {v_terminal:.2f} m/s')\n",
    "\n",
    "plt.xlabel('Tempo (s)', fontsize=11)\n",
    "plt.ylabel('Velocidade (m/s)', fontsize=11)\n",
    "plt.title('Queda Livre: Com e Sem Arrasto', fontsize=12, fontweight='bold')\n",
    "plt.legend(fontsize=10)\n",
    "plt.grid(True, alpha=0.3)\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "## Exercício Proposto 5: Lei de Coulomb Numérica\n",
    "\n",
    "**Desafio:**\n",
    "\n",
    "Implemente o cálculo da força eletrostática entre múltiplas cargas em um espaço 2D.\n",
    "\n",
    "$$F = k \\frac{|q_1 q_2|}{r^2}$$\n",
    "\n",
    "Visualize as forças com vetores."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "source": "k = 8.99e9  # constante de Coulomb\n\ndef distancia(p1, p2):\n    \"\"\"Calcula a distância entre dois pontos.\"\"\"\n    return np.sqrt((p1[0] - p2[0])**2 + (p1[1] - p2[1])**2)\n\ndef campo_eletrico(x, y, cargas):\n    \"\"\"\n    Calcula o campo elétrico em um ponto (x, y) devido a múltiplas cargas.\n    \n    Args:\n        x, y: coordenadas do ponto\n        cargas: lista de tuplas (x_carga, y_carga, q_carga)\n    \n    Returns:\n        Ex, Ey: componentes do campo elétrico\n    \"\"\"\n    Ex, Ey = 0, 0\n    \n    for x_c, y_c, q in cargas:\n        r = distancia((x, y), (x_c, y_c))\n        \n        if r < 0.1:  # Evitar singularidade muito próxima\n            continue\n        \n        # Campo elétrico = k*q/r² (magnitud)\n        E = k * q / (r**2)\n        \n        # Componentes\n        cos_theta = (x - x_c) / r\n        sin_theta = (y - y_c) / r\n        \n        Ex += E * cos_theta\n        Ey += E * sin_theta\n    \n    return Ex, Ey\n\ndef potencial_eletrico(x, y, cargas):\n    \"\"\"Calcula o potencial elétrico em um ponto.\"\"\"\n    V = 0\n    for x_c, y_c, q in cargas:\n        r = distancia((x, y), (x_c, y_c))\n        if r < 0.05:\n            continue\n        V += k * q / r\n    return V\n\n# Sistema de 3 cargas\ncargas = [\n    (-1, 0, 1e-6),      # +1 µC\n    (1, 0, 1e-6),       # +1 µC\n    (0, 1.5, -2e-6),    # -2 µC\n]\n\n# Grade para cálculos\nx = np.linspace(-3, 3, 40)\ny = np.linspace(-3, 3, 40)\nX, Y = np.meshgrid(x, y)\n\n# Calcular campo elétrico\nU = np.zeros_like(X)\nV_pot = np.zeros_like(X)\n\nfor i in range(len(x)):\n    for j in range(len(y)):\n        U[i, j], V_pot[i, j] = campo_eletrico(X[i, j], Y[i, j], cargas)\n\n# Calcular potencial\nfor i in range(len(x)):\n    for j in range(len(y)):\n        V_pot[i, j] = potencial_eletrico(X[i, j], Y[i, j], cargas)\n\n# Normalizar campo para streamplot\nE_magnitude = np.sqrt(U**2 + V_pot**2)\nU_norm = np.log10(E_magnitude + 1) * np.sign(U)\nV_norm = np.log10(E_magnitude + 1) * np.sign(V_pot)\n\n# Visualização\nfig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6))\n\n# Painel 1: Linhas de campo com streamplot\nstrm = ax1.streamplot(X, Y, U_norm, V_norm, color=np.log10(E_magnitude + 1), \n                      cmap='hot', density=1.5, linewidth=1)\ncbar1 = plt.colorbar(strm.lines, ax=ax1, label='log₁₀(|E|)')\n\n# Marcar cargas\nfor x_c, y_c, q in cargas:\n    cor = 'red' if q > 0 else 'blue'\n    marcador = '+' if q > 0 else '_'\n    ax1.scatter(x_c, y_c, s=300, c=cor, marker='o', edgecolors='black', linewidth=2, zorder=5)\n\nax1.set_xlabel('x (m)', fontsize=11)\nax1.set_ylabel('y (m)', fontsize=11)\nax1.set_title('Linhas de Campo Elétrico', fontsize=12, fontweight='bold')\nax1.set_xlim(-3, 3)\nax1.set_ylim(-3, 3)\nax1.grid(True, alpha=0.2)\n\n# Painel 2: Equipotenciais com contourf\ncontourf = ax2.contourf(X, Y, V_pot, levels=20, cmap='viridis')\ncontour = ax2.contour(X, Y, V_pot, levels=10, colors='white', linewidths=0.5, alpha=0.5)\nax2.clabel(contour, inline=True, fontsize=8)\ncbar2 = plt.colorbar(contourf, ax=ax2, label='Potencial V (V)')\n\n# Marcar cargas\nfor x_c, y_c, q in cargas:\n    cor = 'red' if q > 0 else 'blue'\n    ax2.scatter(x_c, y_c, s=300, c=cor, marker='o', edgecolors='white', linewidth=2, zorder=5)\n\nax2.set_xlabel('x (m)', fontsize=11)\nax2.set_ylabel('y (m)', fontsize=11)\nax2.set_title('Equipotenciais (Linhas de Potencial Constante)', fontsize=12, fontweight='bold')\nax2.set_xlim(-3, 3)\nax2.set_ylim(-3, 3)\nax2.grid(True, alpha=0.2)\n\nplt.tight_layout()\nplt.show()\n\nprint(\"=== CAMPO ELETROSTÁTICO 2D ===\")\nprint(\"\\nCargas no sistema:\")\nfor i, (x_c, y_c, q) in enumerate(cargas, 1):\n    print(f\"Carga {i}: q = {q*1e6:.1f} µC em ({x_c}, {y_c})\")",
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "## Exercício Proposto 6: Oscilador Harmônico Amortecido\n",
    "\n",
    "**Desafio:**\n",
    "\n",
    "Simule o movimento de um oscilador harmônico com amortecimento:\n",
    "\n",
    "$$\\frac{d^2x}{dt^2} + 2\\gamma\\frac{dx}{dt} + \\omega_0^2 x = 0$$\n",
    "\n",
    "Teste para diferentes graus de amortecimento (subamortecido, criticamente amortecido, superamortecido)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "source": "def oscilador_amortecido(condicoes_iniciais, omega0, gamma, t_total):\n    \"\"\"\n    Simula oscilador harmônico amortecido.\n    \n    EDO: d²x/dt² + 2γ(dx/dt) + ω₀²x = 0\n    \n    Args:\n        condicoes_iniciais: [x0, v0]\n        omega0: frequência natural\n        gamma: coeficiente de amortecimento\n        t_total: tempo total de simulação\n    \n    Returns:\n        t, x, v: tempo, deslocamento, velocidade\n    \"\"\"\n    def derivadas(y, t, omega0, gamma):\n        x, v = y\n        dx_dt = v\n        dv_dt = -2 * gamma * v - omega0**2 * x\n        return [dx_dt, dv_dt]\n    \n    t = np.linspace(0, t_total, 1000)\n    solucao = odeint(derivadas, condicoes_iniciais, t, args=(omega0, gamma))\n    \n    return t, solucao[:, 0], solucao[:, 1]\n\n# Parâmetros\nomega0 = 2.0  # frequência natural (rad/s)\nx0 = 1.0      # deslocamento inicial\nv0 = 0        # velocidade inicial\n\n# Três regimes de amortecimento\n# Subamortecido: γ < ω₀\n# Criticamente amortecido: γ = ω₀\n# Superamortecido: γ > ω₀\n\nregimes = [\n    (0.5, \"Subamortecido (γ=0.5, γ<ω₀)\"),\n    (2.0, \"Criticamente amortecido (γ=2.0, γ=ω₀)\"),\n    (3.0, \"Superamortecido (γ=3.0, γ>ω₀)\"),\n]\n\n# Simulações\nfig, axes = plt.subplots(2, 3, figsize=(16, 9))\n\nfor idx, (gamma, titulo) in enumerate(regimes):\n    t, x, v = oscilador_amortecido([x0, v0], omega0, gamma, 10)\n    \n    # Painel superior: deslocamento\n    ax = axes[0, idx]\n    ax.plot(t, x, 'b-', linewidth=2, label='x(t)')\n    \n    # Envelope exponencial para subamortecido\n    if gamma < omega0:\n        envelope = x0 * np.exp(-gamma * t)\n        ax.plot(t, envelope, 'r--', linewidth=1, alpha=0.7, label='Envelope: exp(-γt)')\n        ax.plot(t, -envelope, 'r--', linewidth=1, alpha=0.7)\n    \n    ax.axhline(0, color='k', linewidth=0.5, alpha=0.5)\n    ax.set_ylabel('Deslocamento x (m)', fontsize=10)\n    ax.set_title(titulo, fontsize=11, fontweight='bold')\n    ax.grid(True, alpha=0.3)\n    ax.legend(fontsize=9)\n    if idx == 0:\n        ax.set_ylabel('Deslocamento x (m)', fontsize=10, fontweight='bold')\n    \n    # Painel inferior: retrato de fase (x vs v)\n    ax = axes[1, idx]\n    ax.plot(x, v, 'g-', linewidth=2)\n    ax.scatter(x0, v0, s=100, c='red', marker='o', zorder=5, label='Inicial')\n    ax.scatter(0, 0, s=100, c='black', marker='x', zorder=5, label='Equilíbrio')\n    \n    # Adicionar setas para mostrar direção\n    for i in range(0, len(t), 50):\n        if i + 1 < len(t):\n            ax.annotate('', xy=(x[i+1], v[i+1]), xytext=(x[i], v[i]),\n                       arrowprops=dict(arrowstyle='->', color='green', alpha=0.5))\n    \n    ax.set_xlabel('Deslocamento x (m)', fontsize=10)\n    ax.set_ylabel('Velocidade v (m/s)', fontsize=10)\n    ax.set_title(f'Retrato de Fase - {titulo.split(\"(\")[0].strip()}', fontsize=11, fontweight='bold')\n    ax.grid(True, alpha=0.3)\n    ax.legend(fontsize=9)\n    if idx == 0:\n        ax.set_ylabel('Velocidade v (m/s)', fontsize=10, fontweight='bold')\n\nplt.suptitle('Oscilador Harmônico Amortecido - Três Regimes de Amortecimento', \n             fontsize=13, fontweight='bold', y=0.995)\nplt.tight_layout()\nplt.show()\n\nprint(\"=== OSCILADOR HARMÔNICO AMORTECIDO ===\")\nprint(f\"\\nParâmetros:\")\nprint(f\"  Frequência natural: ω₀ = {omega0} rad/s\")\nprint(f\"  Deslocamento inicial: x₀ = {x0} m\")\nprint(f\"  Velocidade inicial: v₀ = {v0} m/s\")\nprint(f\"\\nRegimes:\")\nprint(f\"  Subamortecido (γ < ω₀): oscila com amplitude decrescente\")\nprint(f\"  Criticamente amortecido (γ = ω₀): retorna ao equilíbrio mais rápido sem oscilar\")\nprint(f\"  Superamortecido (γ > ω₀): retorna lentamente sem oscilar\")",
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "source": "---\n\n## Análise Big-O: Complexidade Computacional\n\n**Tema:** Medir empiricamente a complexidade de tempo de algoritmos de busca.\n\nComparar busca linear O(n) vs busca binária O(log n).",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "source": "import time\nimport bisect\n\ndef busca_linear(lista, alvo):\n    \\\"\\\"\\\"Busca linear: O(n) - verifica cada elemento.\\\"\\\"\\\"\\n    for i, elemento in enumerate(lista):\\n        if elemento == alvo:\\n            return i\\n    return -1\\n\\ndef busca_binaria(lista, alvo):\\n    \\\"\\\"\\\"Busca binária: O(log n) - divide e conquista.\\\"\\\"\\\"\\n    esquerda, direita = 0, len(lista) - 1\\n    \\n    while esquerda <= direita:\\n        meio = (esquerda + direita) // 2\\n        if lista[meio] == alvo:\\n            return meio\\n        elif lista[meio] < alvo:\\n            esquerda = meio + 1\\n        else:\\n            direita = meio - 1\\n    \\n    return -1\\n\\n# Teste com diferentes tamanhos\\ntamanhos = [1000, 5000, 10000, 50000, 100000, 500000, 1000000]\\ntempos_linear = []\\ntempos_binaria = []\\n\\nprint(\\\"=== ANÁLISE DE COMPLEXIDADE (BIG-O) ===\\\")\\nprint(f\\\"{'Tamanho':<10} | {'Linear (ms)':<15} | {'Binária (ms)':<15} | {'Razão':<10}\\\")\\nprint(\\\"-\\\" * 55)\\n\\nfor tamanho in tamanhos:\\n    # Criar lista ordenada\\n    lista = list(range(tamanho))\\n    alvo = tamanho // 2  # Buscar elemento no meio\\n    \\n    # Medir tempo - busca linear\\n    num_tentativas = 100 if tamanho <= 10000 else 10\\n    inicio = time.perf_counter()\\n    for _ in range(num_tentativas):\\n        busca_linear(lista, alvo)\\n    tempo_linear = (time.perf_counter() - inicio) / num_tentativas * 1000\\n    \\n    # Medir tempo - busca binária\\n    inicio = time.perf_counter()\\n    for _ in range(num_tentativas):\\n        busca_binaria(lista, alvo)\\n    tempo_binaria = (time.perf_counter() - inicio) / num_tentativas * 1000\\n    \\n    tempos_linear.append(tempo_linear)\\n    tempos_binaria.append(tempo_binaria)\\n    \\n    razao = tempo_linear / tempo_binaria if tempo_binaria > 0 else float('inf')\\n    print(f\\\"{tamanho:<10} | {tempo_linear:<15.4f} | {tempo_binaria:<15.4f} | {razao:<10.1f}x\\\")\\n\\n# Visualização\\nfig, axes = plt.subplots(1, 2, figsize=(14, 5))\\n\\n# Painel 1: Escala linear\\nax = axes[0]\\nax.plot(tamanhos, tempos_linear, 'b-o', linewidth=2.5, markersize=8, label='Busca Linear (O(n))')\\nax.plot(tamanhos, tempos_binaria, 'r-s', linewidth=2.5, markersize=8, label='Busca Binária (O(log n))')\\nax.set_xlabel('Tamanho da lista (n)', fontsize=11, fontweight='bold')\\nax.set_ylabel('Tempo (ms)', fontsize=11, fontweight='bold')\\nax.set_title('Complexidade: Escala Linear', fontsize=12, fontweight='bold')\\nax.legend(fontsize=11)\\nax.grid(True, alpha=0.3)\\n\\n# Painel 2: Escala logarítmica (log-log)\\nax = axes[1]\\nax.loglog(tamanhos, tempos_linear, 'b-o', linewidth=2.5, markersize=8, label='Linear: O(n)')\\nax.loglog(tamanhos, tempos_binaria, 'r-s', linewidth=2.5, markersize=8, label='Binária: O(log n)')\\n\\n# Linhas de referência\\nn_ref = np.array([1000, 1000000])\\nax.loglog(n_ref, 0.0001 * n_ref, 'b--', alpha=0.4, linewidth=1.5, label='Referência: ~n')\\nax.loglog(n_ref, 0.1 * np.log2(n_ref), 'r--', alpha=0.4, linewidth=1.5, label='Referência: ~log₂(n)')\\n\\nax.set_xlabel('Tamanho da lista (n) - escala log', fontsize=11, fontweight='bold')\\nax.set_ylabel('Tempo (ms) - escala log', fontsize=11, fontweight='bold')\\nax.set_title('Complexidade: Escala Log-Log', fontsize=12, fontweight='bold')\\nax.legend(fontsize=10)\\nax.grid(True, alpha=0.3, which='both')\\n\\nplt.tight_layout()\\nplt.show()\\n\\nprint(\\\"\\\\n=== INTERPRETAÇÃO ===\\\")\\nprint(\\\"\\\\nBusca Linear (O(n)):\\\")\\nprint(\\\"  • Tempo cresce linearmente com o tamanho\\\")\\nprint(\\\"  • Cada duplicação do tamanho duplica o tempo\\\")\\nprint(\\\"  • Adequada para listas pequenas\\\")\\nprint(\\\"\\\\nBusca Binária (O(log n)):\\\")\\nprint(\\\"  • Tempo cresce logaritmicamente\\\")\\nprint(\\\"  • Aumentar 1.000.000x o tamanho só quadruplica o tempo!\\\")\\nprint(\\\"  • Requer lista ordenada\\\")\\nprint(\\\"  • Muito mais eficiente para listas grandes\\\")\"",
   "metadata": {},
   "execution_count": null,
   "outputs": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "name": "python",
   "version": "3.9.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}