4.1. Conceitos Fundamentais¶
1.1. Calcule a área de um círculo de raio 2. Assuma pi = 3.14.
radius, pi = 2, 3.14
pi * radius ** 2
12.56
1.2. Escreva uma função que verifica se um número é par. Se for, imprima uma mensagem. Se não for, imprima outra mensagem.
def is_even(x):
if x % 2 == 0:
print('Number {} is even'.format(x))
else:
print('Number {} is odd'.format(x))
is_even(2)
is_even(3)
Number 2 is even
Number 3 is odd
1.3. No exercício acima, se o número for par, verifique se ele é múltiplo de 4. Se for, exiba uma mensagem diferente.
def is_even(x):
if x % 2 == 0:
message = 'Number {} is even'.format(x)
if x % 4 == 0:
message = ' '.join([message, 'and is a multiple of 4'])
print(message)
else:
print('Number {} is odd'.format(x))
is_even(2)
is_even(3)
is_even(64)
Number 2 is even
Number 3 is odd
Number 64 is even and is a multiple of 4
1.4. Escreva um código que imprima os elementos menores que 5 na seguinte lista:
a = [1, 4, 2, 3, 2, 1, 5, 8, 5, 7, -1, 0, 23]
[x for x in a if x < 5 ]
[1, 4, 2, 3, 2, 1, -1, 0]
1.5. Escreva um código que encontra todos os divisores do número 42.
divisors = [i for i in range(1, 43) if 42 % i == 0]
divisors
[1, 2, 3, 6, 7, 14, 21, 42]
1.6. Calcule a multiplicação das duas matrizes abaixo sem usar laços:
a = [[2, 3], [4, 2]]
b = [[2, 0], [1, 2]]
print(
[
[
a[0][0] * b[0][0] + a[0][1] * b[1][0],
a[0][0] * b[0][1] + a[0][1] * b[1][1]
],
[
a[1][0] * b[0][0] + a[1][1] * b[1][0],
a[1][0] * b[0][1] + a[1][1] * b[1][1]
]
]
)
[[7, 6], [10, 4]]
1.7. Calcule a multiplicação das duas matrizes acima usando laços
mul = [[0 for _ in range(2)] for _ in range(2)]
for i in range(2):
for j in range(2):
for c in range(2):
mul[i][c] += a[i][j] * b[j][c]
mul
[[7, 6], [10, 4]]
1.8. Calcule o fatorial de 5 usando algum tipo de laço.
prod = 1
for i in range(1, 6):
prod *= i
prod
120
1.9. Dada uma variável \(X \sim N(0, 4)\), calcule o valor da fdp para o valor 2.
import math
x, mu, sigma_2 = 2, 0, 4
fdp = (math.e ** (-(x - mu) ** 2 / (2 * sigma_2))) / math.sqrt(2 * math.pi * sigma_2)
fdp
0.12098536225957168
1.10. Calcule a distância Euclidiana dos seguintes vetores:
import math
a, b = [1, 0, 1], [-1, 2, 3]
total = 0
for i in range(len(a)):
total += (a[i] - b[i]) ** 2
print(math.sqrt(total))
3.4641016151377544
1.11. Imprima as potências de 2, começando em \(2^0\), enquanto o resultado for menor do que 2000.
v = 1
while v < 2000:
print(v)
v *= 2
1
2
4
8
16
32
64
128
256
512
1024
1.12. Verifique se o número 79 é primo.
number = 2
x = 79
while number < x:
if x % number == 0:
print('{} is not prime'.format(x))
break
number += 1
else:
print('{} is prime'.format(x))
79 is prime
1.13. Escreva uma linha de código Python que gere uma lista apenas com os valores divisíveis por 2 e por 5 na lista abaixo:
a = [1, 4, 10, 13, 15, 16, 20, 28, 30]
[x for x in a if x % 2 == 0 and x % 5 == 0]
[10, 20, 30]
1.14. Escreva um laço que resulte no elemento de índice 7 da sequência de Fibonacci (lembrando que em Python os índices começam em 0):
first = 0
second = 1
value = 0
for i in range(1, 7):
value = first + second
first = second
second = value
value
13
1.15. Escreva uma função que calcule o raio de um círculo, dado um valor de raio. Peça um valor de raio ao usuário e calcule o valor da função.
import math
def circle_area(radius):
return math.pi * radius ** 2
radius = float(input('Type a radius value: '))
circle_area(radius)
---------------------------------------------------------------------------
StdinNotImplementedError Traceback (most recent call last)
<ipython-input-15-e6e6e6f203bd> in <module>
4 return math.pi * radius ** 2
5
----> 6 radius = float(input('Type a radius value: '))
7 circle_area(radius)
~/anaconda2/envs/py37/lib/python3.7/site-packages/ipykernel/kernelbase.py in raw_input(self, prompt)
856 if not self._allow_stdin:
857 raise StdinNotImplementedError(
--> 858 "raw_input was called, but this frontend does not support input requests."
859 )
860 return self._input_request(str(prompt),
StdinNotImplementedError: raw_input was called, but this frontend does not support input requests.
1.16. Escreva uma função que recebe uma lista e um valor e retorna uma sub-lista apenas com os elementos menores do que o valor fornecido.
def less_than(l, v):
return [x for x in l if x < v]
less_than([5, 1, 2, 5, 0, 9, -1, 11, 5, 4], 5)
[1, 2, 0, -1, 4]
1.17. Escreva uma função que calcula a multiplicação de duas matrizes usando laços, mas apenas se as dimensões das matrizes forem compatíveis.
def mul(a, b):
n_cols_a = len(a[0])
n_rows_b = len(b)
if n_cols_a == n_rows_b:
n_rows_a = len(a)
n_cols_b = len(b[0])
mul = [[0 for _ in range(n_cols_b)] for _ in range(n_rows_a)]
for i in range(n_rows_a):
for j in range(n_cols_a):
for c in range(n_cols_b):
mul[i][c] += a[i][j] * b[j][c]
return mul
else:
return 'Incompatible dimensions'
a = [[2, 3], [4, 2]]
b = [[2, 0], [1, 2]]
c = [[2, 3], [4, 2], [0, 1]]
d = [[2, 3, 0], [4, 2, 1]]
mul(a, b), mul(c, b), mul(d, a)
([[7, 6], [10, 4]], [[7, 6], [10, 4], [1, 2]], 'Incompatible dimensions')
1.18. Escreva uma função que recebe um número e valores de média e de variância e calcula a fdp das distribuições normais correspondentes às médias e às variâncias fornecidas.
import math
def normal_fdp(x, mu, sigma_2):
return (math.e ** (-(x - mu) ** 2 / (2 * sigma_2))) / math.sqrt(2 * math.pi * sigma_2)
def fdp_list(x, means, variances):
return [normal_fdp(x, mu, sigma_2) for mu, sigma_2 in zip(means, variances)]
fdp_list(2, [0, 2, -1], [1, 0.5, 2])
[0.05399096651318806, 0.5641895835477563, 0.029732572305907347]
1.19. Escreva uma função que verifica se um número é primo.
def is_prime(n):
number = 2
while number < n:
if x % number == 0:
return False
break
number += 1
else:
return True
is_prime(79), is_prime(100)
(True, False)
1.20. Faça uma função que retorna todos os divisores de um número.
def divisors(n):
return [i for i in range(1, n + 1) if n % i == 0]
divisors(84)
[1, 2, 3, 4, 6, 7, 12, 14, 21, 28, 42, 84]
1.21. Faça uma função que calcula o fatorial de um número.
def factorial(n):
prod = 1
for i in range(1, n + 1):
prod *= i
return prod
factorial(0), factorial(1), factorial(5)
(1, 1, 120)
1.22. Faça uma função que calcula \(P(X = x)\), tal que \(X \sim Binomial(n, p)\). Escreva uma função auxiliar que calcula \({n}\choose{x}\) para chamar na função principal.
def factorial(n):
prod = 1
for i in range(1, n + 1):
prod *= i
return prod
def combination(n, x):
return factorial(n) / (factorial(x) * factorial(n - x))
def binomial(x, n, p):
return combination(n, x) * p ** x * (1.0 - p) ** (n - x)
binomial(2, 5, 0.7)
0.13230000000000006
1.23. Escreva uma função que calcula \(P(X = x)\) ou \(P(X <= x)\) (o usuário escolhe), tal que \(X \sim Binomial(n, p)\).
def factorial(n):
prod = 1
for i in range(1, n + 1):
prod *= i
return prod
def combination(n, x):
return factorial(n) / (factorial(x) * factorial(n - x))
def binomial(x, n, p, cumulative=False):
prob = combination(n, x) * p ** x * (1.0 - p) ** (n - x)
if cumulative:
total = 0
for i in range(x):
total += combination(n, i) * p ** i * (1.0 - p) ** (n - i)
prob = total + prob
return prob
binomial(2, 5, 0.7, cumulative=True)
0.16308000000000009
1.24. Escreva uma função que recebe uma lista, um valor e uma função de comparação e retorna uma sub-lista apenas com os elementos para os quais a função fornecida retorna True.
def sub_list(l, target, func):
return [x for x in l if func(x, target)]
sub_list([5, 1, 2, 5, 0, 9, -1, 11, 5, 4], 5, lambda x,v: x != v)
[1, 2, 0, 9, -1, 11, 4]
1.25. (Desafio: Recursão). Recursão é uma abordagem para solucionar problemas que envolve dividir a tarefa em partes menores do mesmo tipo, i.e. é uma abordagem do tipo dividir-para-conquistar. Do ponto de vista computacional, um problema resolvido usando recursão envolve uma função que chama a si mesma até que o problema seja resolvido. Uma parte importante desse tipo de solução é a definição do ponto de parada da recursão, quando a função para de chamar a si mesma e começar a retornar os valores para as chamadas mais “acima”. Vejamos um exemplo de recursão para o cálculo do fatorial de um número n:
def factorial(n):
if n == 0:
return 1
else:
return n * factorial(n - 1)
factorial(0), factorial(1), factorial(5)
(1, 1, 120)
Agora implemente uma função recursiva que recebe um número e retorna o número correspondente na sequência de Fibonacci.
def fibonacci(n):
if n == 0:
return 0
elif n == 1:
return 1
else:
return fibonacci(n - 2) + fibonacci(n - 1)
fibonacci(0), fibonacci(1), fibonacci(20)
(0, 1, 6765)
1.26. (Algoritmo de ordenação: Bubble sort). Bubble sort é um algoritmo muito simples. Ele começa no início da lista e compara os dois primeiros elementos. Se o primeiro for maior do que o segundo, eles são trocados. Esse processo se repete para cada par subsequente, até o final da lista. Depois o algoritmo volta ao início da lista e recomeça o processo, repetindo-o até não haver mais trocas. Implemente uma função que recebe uma lista e retorna seus elementos ordenados usando o algoritmo bubble sort.
def bubble_sort(l):
keepSorting = True
while keepSorting:
keepSorting = False
for i in range(len(l) - 1):
if l[i] > l[i + 1]:
temp = l[i + 1]
l[i + 1] = l[i]
l[i] = temp
keepSorting = True
return l
l = [10, 1, 2, 8, 0, 9, -1, 11, 5, 4]
bubble_sort(l)
[-1, 0, 1, 2, 4, 5, 8, 9, 10, 11]
1.27. (Algoritmo de ordenação: Insertion sort). Algoritmo relativamente eficiente para listas pequenas e comumente usado como parte de algoritmos mais sofisticados. Ele funciona da seguinte maneira: a cada iteração, o algoritmo remove um elemento da lista, encontra seu lugar na lista ordenada e insere o elemento. Assim, a parte ordenada da lista cresce a cada iteração. A ordenação é feita na própria lista. A cada posição da lista, o algoritmo compara seu valor com o maior valor da parte ordenada. Se for maior, o elemento é mntido e o algoritmo passa para a próxima posição. Se for menor, ele acha a posição correta do elemento na parte ordenada e move todos os valores maiores para abrir espaço e inserir o elemento. Implemente uma função que recebe uma lista e retorna seus elementos ordenados usando o algoritmo insertion sort.
def insertion_sort(l):
for i in range(1, len(l)):
key = l[i]
k =i
while k > 0 and key < l[k - 1]:
l[k] = l[k - 1]
k -= 1
l[k] = key
return l
l = [10, 1, 2, 8, 0, 9, -1, 11, 5, 4]
insertion_sort(l)
[-1, 0, 1, 2, 4, 5, 8, 9, 10, 11]
1.28. (Algoritmo de ordenação: Selection sort). O selection sort divide o array de entrada em duas partes: a parte ordenada, que ocupa a extremidade esquerda do array, e a parte não-ordenada, que ocupa a parte direita do array. O algoritmo busca o menor elemento da parte não-ordenada e o troca com o elemento mais à esquerda da parte não-ordenada, movendo a fronteira entre as duas partes do array uma posição para a direita. O selection sort é quadrático em todos os casos. Implemente uma função que recebe uma lista e retorna seus elementos ordenados usando o algoritmo selection sort.
def selection_sort(l):
for i in range(len(l) - 1):
j_minimum = i
for j in range(i + 1, len(l)):
if l[j] < l[j_minimum]:
j_minimum = j
temp = l[j_minimum]
l[j_minimum] = l[i]
l[i] = temp
return l
l = [10, 1, 2, 8, 0, 9, -1, 11, 5, 4]
selection_sort(l)
[-1, 0, 1, 2, 4, 5, 8, 9, 10, 11]
1.29. (Algoritmo de ordenação: Merge sort). Usa a abordagem dividir para conquistar, aproveitando-se da facilidade de unir duas listas ordenadas em uma nova lista. O algoritmo divide a lista em n listas, cada uma com um elemeno. Uma lista com 1 elemento é considerada ordenada. Depois, o algoritmo repetidamente une arrays adjacentes, produzindo novos arrays ordenados, até que o único array restante contenha todos os elementos ordenados. Para unir dois arrays ordenados, o algoritmo seleciona o menor elemento de cada array e os compara, colocando o menor na primeira posição livre do novo array, e comparando o elemento que sobrou com o novo menor elemento do outro array e assim sucessivamente. Implemente uma função que recebe uma lista e retorna seus elementos ordenados usando o algoritmo merge sort.
def merge_sort(l):
if len(l) > 1:
middle = len(l)//2
#também é valido: middle = int(len(l)/2)
left_list = l[:middle]
right_list = l[middle:]
left_list = merge_sort(left_list)
right_list = merge_sort(right_list)
i = 0
j = 0
k = 0
while i < len(left_list) and j < len(right_list):
if left_list[i] < right_list[j]:
l[k] = left_list[i]
i += 1
else:
l[k] = right_list[j]
j += 1
k += 1
while i < len(left_list):
l[k] = left_list[i]
i += 1
k += 1
while j < len(right_list):
l[k] = right_list[j]
j += 1
k += 1
return l
l = [10, 1, 2, 8, 0, 9, -1, 11, 5, 4]
print(merge_sort(l))
[-1, 0, 1, 2, 4, 5, 8, 9, 10, 11]
1.30. (Algoritmo de ordenação: Quicksort). Assim como o merge sort, o quicksort é um algoritmo que usa a abordagem dividir para conquistar, mais especificamente, uma abordagem de partição. O algoritmo seleciona um elemento, chamado de pivô, e coloca todos os elementos menores do que o pivô antes dele e todos os maiores depois dele. Os dois sub-arrays são então recursivamente ordenados, seguindo o mesmo processo. Implementações eficientes do quicksort estão entre os algoritmos de ordenação mais rápidos na prática. Implemente uma função que recebe uma lista e retorna seus elementos ordenados usando o algoritmo quicksort.
def quicksort(l, ini, end):
i = ini
j = end
index_pivot = (ini + end) // 2
pivot = l[index_pivot]
while i <= j:
while l[i] < pivot:
i += 1
while l[j] > pivot:
j -= 1
if i <= j:
temp = l[i]
l[i] = l[j]
l[j] = temp
i += 1
j -= 1
if ini < j:
quicksort(l, ini, j)
if i < end:
quicksort(l, i, end)
return l
l = [10, 1, 2, 8, 0, 9, -1, 11, 5, 4]
quicksort(l, 0, len(l) - 1)
[-1, 0, 1, 2, 4, 5, 8, 9, 10, 11]