Aula 09: Funções

Tópicos

Aulas a distância - Google Meet:

Para verem os vídeos, vocês devem estar logados no e-mail da usp.

Uma função é uma unidade de código de programa autônoma desenhada para cumprir uma tarefa particular.

A chamada de uma função desvia a execução do código para o corpo da função (bloco de código da função):

chamada_funcao

Motivação:

Exemplo 1: coeficiente binomial

Problema 1:

  1. Escreva a função fatorial(n) que recebe um inteiro n e devolve o fatorial de n.

  2. Escreva uma função que recebe dois inteiros n e k e calcula o coeficiente binomial, do número n, na classe k, isto é, o número de combinações de n termos, k a k, dado por n!/(k!(n-k)!). Escreva essa função usando a função fatorial(n) do item anterior.

  3. Faça um programa que lê um número inteiro n, com n > 0, e que imprime o Triângulo de Pascal com n linhas.

Exemplo: Triângulo de Pascal com sete linhas (n = 7).

triangulo_pascal

Solução 1:

Os elementos do triângulo de Pascal correspondem a valores do coeficiente binomial, tal como indicado na figura abaixo:

triangulo_pascal

def fatorial(n):
    fat = 1
    i = 2
    while i <= n:
        fat *= i
        i += 1
    return fat

def binomial(n, k):
    num = fatorial(n)               #numerador
    den = fatorial(k)*fatorial(n-k) #denominador
    return num//den
	       
def main():
    print("Triângulo de Pascal")
    n = int(input("Digite o número de linhas: "))
    i = 0
    while i < n:
        j = 0
        while j <= i:
            b = binomial(i,j)
            print("%3d "%b,end="")
            j+= 1
        print()
        i += 1

main()
  

Solução 2:

A função que calcula o coeficiente binomial pode ser escrita de modo mais compacto, realizando as três chamadas do fatorial em uma mesma linha, ao invés de usar as variáveis auxiliares num e den.

  
def binomial(n,k):
    return fatorial(n)//(fatorial(k)*fatorial(n-k))
  
Observe, no entanto, a necessidade do uso do parênteses para garantir a ordem correta das operações.

Solução 3:

Note que poderíamos simplificar a fração eliminando os fatores em comum presentes no numerador e denominador, antes de calcular o coeficiente binomial, poupando esforço computacional. Observe que tanto k quanto (n-k) são menores ou iguais a n. Logo, podemos usar qualquer uma das simplificações abaixo:

matriz

matriz

Se k for maior do que (n-k), é preferível utilizar a primeira simplificação. Caso contrário, optamos pela segunda.

Observe, no entanto, que o numerador das versões simplificadas já não mais corresponde ao cálculo do fatorial, pois o produtório agora vai de n até (k+1) ou (n-k+1), e não mais até 1. Vamos então criar uma função auxiliar com uma versão generalizada do fatorial, que possui um parâmetro adicional, permitindo especificar o início do intervalo do produtório.

Temos então a seguinte solução:

#Fatorial generalizado.
#Calcula o produtório: inic*(inic+1)*...*(n-1)*n	       
#Se inic=1, então equivale ao fatorial.
def fatorial_gen(inic, n):
    fat = 1
    i = inic
    while i <= n:
        fat *= i
        i += 1
    return fat

def binomial(n, k):
    if k > n-k:
        den = fatorial(n-k)           #denominador
        num = fatorial_gen(k+1, n)    #numerador
    else:
        den = fatorial(k)             #denominador
        num = fatorial_gen(n-k+1, n)  #numerador
    return num//den       
  

Solução 4:

Solução similar à anterior, porém utiliza duas funções auxiliares para ajudar na seleção do maior e menor valor entre k e (n-k).

#Fatorial generalizado.
#Calcula o produtório: inic*(inic+1)*...*(n-1)*n	       
#Se inic=1, então equivale ao fatorial.
def fatorial_gen(inic, n):
    fat = 1
    i = inic
    while i <= n:
        fat *= i
        i += 1
    return fat

def maior(a, b):
    if a > b:
        m = a
    else:
        m = b
    return m

def menor(a, b):
    if a < b:
        m = a
    else:
        m = b
    return m	       

def binomial(n, k):
    den = fatorial(menor(k, n-k))
    num = fatorial_gen(maior(k, n-k)+1, n)
    return num//den
  

Solução 5:

Solução idêntica à anterior, porém utiliza as funções nativas do Python max() e min().

#Fatorial generalizado.
#Calcula o produtório: inic*(inic+1)*...*(n-1)*n	       
#Se inic=1, então equivale ao fatorial.
def fatorial_gen(inic, n):
    fat = 1
    i = inic
    while i <= n:
        fat *= i
        i += 1
    return fat
    
def binomial(n, k):
    den = fatorial(min(k, n-k))
    num = fatorial_gen(max(k, n-k)+1, n)
    return num//den
  

Problema 2:

Faça um programa que lê um número inteiro n, com n > 0, e para cada número entre 1 e n indica se ele é soma de dois primos.

Por exemplo, para n = 8 o programa deve escrever

1 não é soma de primos
2 não é soma de primos
3 não é soma de primos
4 é soma dos primos 2 e 2
5 é soma dos primos 2 e 3
6 é soma dos primos 3 e 3
7 é soma dos primos 2 e 5
8 é soma dos primos 3 e 5
def primo(n):
    div = 2
    ehprimo = True
    while div < n:
        if n % div == 0:
            ehprimo = False
        div += 1
    if n <= 1:
        ehprimo = False
    return ehprimo

def main():
    n = int(input("Digite n: "))
    i = 1
    while i <= n:
        encontrou = False
        j = 2
        while j < i and not encontrou:
            if primo(j) and primo(i-j):
                encontrou = True
                p1 = j
                p2 = i-j
            j += 1
        if encontrou:
            print("%d é soma dos primos %d e %d"%(i,p1,p2))
        else:
            print("%d não é soma de primos"%i)
        i += 1

main()
  

Problema 3:

  1. Usando a função math.sqrt(x) do módulo de matemática da linguagem Python (import math), escreva uma função que recebe as coordenadas cartesianas de dois pontos no plano e devolve a distância entre os pontos.

  2. Faça um programa que lê um ponto origem (x0, y0) e uma sequência de n > 1 pontos e determina o ponto mais próximo do ponto origem.
import math

def distancia(xa,ya, xb,yb):
    """ Calcula a distancia entre dois pontos"""
    dx = xb-xa
    dy = yb-ya
    d = math.sqrt(dx*dx + dy*dy)
    return d    

def main():
    x0 = float(input("Digite x0 da origem: "))
    y0 = float(input("Digite y0 da origem: "))
    n = int(input("Digite n:"))

    dmin = -1
    for i in range(0,n,1):
        x = float(input("Digite x%d: "%(i+1)))
        y = float(input("Digite y%d: "%(i+1)))
        d = distancia(x0,y0, x,y)
        if dmin < 0 or d < dmin:
            dmin = d
            xmin = x
            ymin = y
    print("x=%.2f, y=%.2f, d=%.2f"%(xmin,ymin,dmin))

main()

Problema 4:

Escreva uma função que recebe dois inteiros positivos e que calcula o máximo divisor comum (MDC) entre eles usando o algoritmo de Euclides.

O MDC de dois números inteiros é o maior número inteiro que divide ambos sem deixar resto.

Exemplos:

Algoritmo de Euclides: Para dois números A e B:

  1. Se A ≥ B: MDC(A,B) = MDC(A-B, B) = MDC(A%B, B) = MDC(B, A%B)
  2. Se A < B: MDC(A,B) = MDC(B,A)
A repetição deste processo irá gerar sucessivamente números menores, até convergir em zero. Nesse momento, o MDC é o outro número inteiro, maior que zero.

  def MDC(a, b):
      if a < b:
          a,b = b,a
      while b > 0:
          r = a % b
          a = b
          b = r
      return a

  def main():
      print("MDC entre a e b:")
      a = int(input("Digite a: "))
      b = int(input("Digite b: "))
      print("MDC =", MDC(a,b))

  main()
  

Problema 5:

Dados um número inteiro n>0 e uma sequência com n números inteiros maiores do que zero, determinar o máximo divisor comum entre eles. Por exemplo, para a entrada
3 42 30 105
o seu programa deve escrever o número 3.

DICA: O MDC é uma operação associativa:

MDC(A,B,C,D) = MDC(MDC(A,B),C,D) = MDC(MDC(MDC(A,B),C),D)
  def MDC(a, b):
      if a < b:
          a,b = b,a
      while b > 0:
          r = a % b
          a = b
          b = r
      return a

  def main():
      n = int(input("Digite n: "))
      mdc = int(input("Digite o primeiro número: "))
      i = 1
      while i < n:
          num = int(input("Digite o próximo número: "))
          a = mdc
          b = num
          mdc = MDC(a, b)
          i += 1
      print("MDC =",mdc)

  main()