{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Frações - Números Racionais\n",
    "\n",
    "A classe **Fraction** implementa operações numéricas para **[números racionais](https://pt.wikipedia.org/wiki/N%C3%BAmero_racional)** com base na API definida pelo **Rational** em numbers."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Criando Instâncias de Fração\n",
    "\n",
    "Uma simples maneira de criarmos uma instância é através da separação dos valores **numerador** e **denominador**\n",
    "\n",
    "Vejamos exemplos"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1/2 = 1/2\n",
      "2/4 = 1/2\n",
      "3/6 = 1/2\n",
      "5/7 = 5/7\n"
     ]
    }
   ],
   "source": [
    "import fractions\n",
    "\n",
    "fracoes = [(1, 2), (2, 4), (3,6), (5,7)]\n",
    "\n",
    "# O menor denominador comum é mantido à medida que novos valores são calculados.\n",
    "for n, d in fracoes:\n",
    "    f = fractions.Fraction(n, d)\n",
    "    print(f'{n}/{d} = {f}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Outra maneira de criar uma Fração é utilizando uma representação de string de `<numerador> / <denominador>`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2/4 = 1/2\n",
      "3/3 = 1\n",
      "5/2 = 5/2\n",
      "4/8 = 1/2\n"
     ]
    }
   ],
   "source": [
    "frac = ['2/4', '3/3', '5/2', '4/8']\n",
    "\n",
    "for s in frac:\n",
    "    f = fractions.Fraction(s)\n",
    "    print(f'{s} = {f}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As strings também podem usar a notação decimal ou ponto flutuante mais usual de `[<dígitos>].[<Dígitos>]`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.5 = 1/2\n",
      "1.5 = 3/2\n",
      "2.0 = 2\n",
      "5.2 = 26/5\n",
      "3.5 = 7/2\n"
     ]
    }
   ],
   "source": [
    "numeros = ['0.5', '1.5', '2.0', '5.2', '3.5']\n",
    "\n",
    "for s in numeros:\n",
    "    f = fractions.Fraction(s)\n",
    "    print(f'{s} = {f}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Existem métodos de classe para criar instâncias de Fração diretamente de outras representações de valores racionais, como **float** ou **decimal**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1.1 = 2476979795053773/2251799813685248\n",
      "2.2 = 2476979795053773/1125899906842624\n",
      "0.5 = 1/2\n",
      "1.5 = 3/2\n"
     ]
    }
   ],
   "source": [
    "numbers = [1.1, 2.2, 0.5, 1.5]\n",
    "\n",
    "for v in numbers:\n",
    "    print(f'{v} = {fractions.Fraction.from_float(v)}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Observe que, para valores de ponto flutuante que não podem ser expressos exatamente, a representação racional pode produzir resultados inesperados.\n",
    "\n",
    "O uso de **representações decimais** dos valores fornece os resultados esperados:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "import decimal"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.1 = 1/10\n",
      "0.5 = 1/2\n",
      "1.5 = 3/2\n",
      "2.0 = 2\n",
      "2.3 = 23/10\n",
      "5.8 = 29/5\n"
     ]
    }
   ],
   "source": [
    "decimais = [decimal.Decimal('0.1'), \n",
    "          decimal.Decimal('0.5'), \n",
    "          decimal.Decimal('1.5'), \n",
    "          decimal.Decimal('2.0'),\n",
    "          decimal.Decimal('2.3'),\n",
    "          decimal.Decimal('5.8'),]\n",
    "\n",
    "for v in decimais:\n",
    "    print(f'{v} = {fractions.Fraction.from_decimal(v)}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Aritmética\n",
    "\n",
    "Depois que as frações são instanciadas, elas podem ser usadas em **expressões matemáticas** como esperado."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1/2 + 5/4 = 7/4\n",
      "1/2 + 5/4 = -3/4\n",
      "1/2 + 5/4 = 5/8\n",
      "1/2 + 5/4 = 2/5\n"
     ]
    }
   ],
   "source": [
    "f1 = fractions.Fraction(1, 2)\n",
    "f2 = fractions.Fraction(5, 4)\n",
    "\n",
    "print(f'{f1} + {f2} = {f1 + f2}')\n",
    "print(f'{f1} + {f2} = {f1 - f2}')\n",
    "print(f'{f1} + {f2} = {f1 * f2}')\n",
    "print(f'{f1} + {f2} = {f1 / f2}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Aproximando Valores\n",
    "\n",
    "Um recurso útil do **Fraction** é a capacidade de converter um número de ponto flutuante em um valor racional aproximado, limitando o tamanho do denominador."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "PI: 3.141592653589793\n",
      "Sem Limite: 3141592653589793/1000000000000000\n"
     ]
    }
   ],
   "source": [
    "import math\n",
    "\n",
    "f_pi = fractions.Fraction(str(math.pi))\n",
    "\n",
    "print(f'PI: {math.pi}')\n",
    "print(f'Sem Limite: {f_pi}' )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1 = 3\n",
      "6 = 19/6\n",
      "11 = 22/7\n",
      "16 = 22/7\n",
      "21 = 22/7\n",
      "26 = 22/7\n",
      "31 = 22/7\n",
      "36 = 22/7\n",
      "41 = 22/7\n",
      "46 = 22/7\n",
      "51 = 22/7\n",
      "56 = 22/7\n",
      "61 = 179/57\n",
      "66 = 201/64\n",
      "71 = 223/71\n",
      "76 = 223/71\n",
      "81 = 245/78\n",
      "86 = 267/85\n",
      "91 = 267/85\n",
      "96 = 289/92\n"
     ]
    }
   ],
   "source": [
    "for i in range(1, 100, 5):\n",
    "    limited = f_pi.limit_denominator(i)\n",
    "    print(f'{i} = {limited}')"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}