Yábir García Benchakhtir


In [1]:
numero = 78277485

In [2]:
a = numero % 1000; a


Out[2]:
485

In [3]:
b = numero % 100; b


Out[3]:
85

Ejercicio 1

1. Calcula la b-ésima y la a-ésima cifra decimal de π.


In [4]:
from mpmath import mp #Librería usada para modiuficar la precision decimal de PI
from math import sqrt

In [5]:
mp.dps = 1000 #Establecer la precisión que queremos

In [6]:
pi_1000 = mp.pi

In [7]:
print(pi_1000)


3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930381964428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920962829254091715364367892590360011330530548820466521384146951941511609433057270365759591953092186117381932611793105118548074462379962749567351885752724891227938183011949129833673362440656643086021394946395224737190702179860943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901224953430146549585371050792279689258923542019956112129021960864034418159813629774771309960518707211349999998372978049951059731732816096318595024459455346908302642522308253344685035261931188171010003137838752886587533208381420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909216420198

Convenimos que la posición decimal de las decimas está indicada con el 0.


In [8]:
besima = str(pi_1000)[b+2]
print(besima)


3

In [9]:
aesima = str(pi_1000)[a+2]
print(aesima)


7

2. Calcula el conjunto de los divisores naturales del número a ¿Cuánto vale la suma de todos ellos?


In [10]:
#Generador de python que devuelve los divisores de un número n
def divisores(n):
    if n < 1:
        raise ValueError("El número ha de ser natural y mayor que 0")
    div = [] #Complementos de numeros
    for numero in range(1, int(sqrt(n) +1 )):
        if n%numero == 0:
            yield numero #Si es un divisor lo devolvemos
            #En la siguiente iteración comprobamos si su cuadrado
            #no es n. Simpre va a ser <= n ya
            #que buscamos hasta la raiz del numero
            if numero*numero != n:
                #Si no es lo añadimos como divisor
                div = div + [int(n/numero)]

    for divisor in div:
        yield divisor

In [11]:
list(divisores(a))


Out[11]:
[1, 5, 485, 97]

In [12]:
# La suma de los divisores es
sum( list(divisores(a)) )


Out[12]:
588

In [13]:
# Un ejemplo para ver como sería con otro número
list( divisores( 24 ) )


Out[13]:
[1, 2, 3, 4, 24, 12, 8, 6]

In [14]:
sum( list( divisores( 24 ) ) )


Out[14]:
60

3. Calcula el mayor número primo menor que a y el menor número primo mayor que a. Calcula también la suma de todos los primos menores que a.


In [15]:
primos = [2]

In [16]:
#Una lista para almacenar los primos que encontremos
def es_primo(n):
    if n >= 2:
        for y in range(2,int(sqrt(n))+1):
            if not ( n % y ):
                return False
    else:
        return False
    
    return True

In [17]:
for i in range(1,920):
    if es_primo(i):
        primos.append(i)

In [18]:
print(primos)


[2, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919]

Luego el mayor primo < a es


In [19]:
primos [-1]


Out[19]:
919

Vamos a calcular ahora el menor primo > que a. Para ello vamos a recurrir a itertools que es una librería del nucleo de python que nos proporciona funciones para hacer algo próximo a la programación funcional


In [20]:
from itertools import takewhile, count

In [21]:
[x for x in takewhile(lambda x: not es_primo(x), count(a+1))][-1]+1


Out[21]:
487

Luego el siguiente primo mayor que a es 937

4. Calcula el número de ceros en que acaba el factorial de (1000+a)

Una manera de calcular el factorial es usar la librería que trae python.


In [22]:
from math import factorial

In [23]:
#factorial(1000+a)

Tambíen podemos hacernos nuestro propio factorial


In [24]:
from operator import mul
from functools import reduce

In [25]:
def factorial_mio(n):
    return reduce(mul, range(1,n+1))

In [26]:
factorial(1000+a) == factorial_mio(1000+a)


Out[26]:
True

Vemos que da el mismo resultado

El numero de ceros en los que acaba el factorial es:


In [27]:
"""
Para buscar el número de 0 se ha procedido a convertir el número en una cadena de caracteres
invertir la posicion de los digitos, el último pasa a ser el primero y así con el resto de dígitos,
por último se recorre la cadena hasta que se encuentra un dígito distinto de 0
"""

total_ceros = 0
distinto_encontrado = False
numero = str( factorial_mio(1000+a) )[::-1]
while not distinto_encontrado:
    if numero[total_ceros] == '0':
        total_ceros += 1
    else:
        distinto_encontrado = True

In [28]:
total_ceros


Out[28]:
369

Ejercicio 2 Un número natural n es perfecto si la suma de sus divisores distintos de él vale n. Halla los números perfectos menores que 10000.

Ya tenemos una función para calcular los divisores de un número n


In [29]:
def divisores(n):
    if n < 1:
        raise ValueError("El número ha de ser natural y mayor que 0")
    div = [] #Complementos de numeros
    for numero in range(1, int(sqrt(n) +1 )):
        if n%numero == 0:
            yield numero #Si es un divisor lo devolvemos
            #En la siguiente iteración comprobamos si su cuadrado
            #no es n. Simpre va a ser <= n ya
            #que buscamos hasta la raiz del numero
            if numero*numero != n:
                #Si no es lo añadimos como divisor
                div = div + [int(n/numero)]

    for divisor in div:
        yield divisor

La suma de los divisores es (incluyendo al 1 y omitiendo el propio número):


In [30]:
def suma_divisores(n):
    divis = list(divisores(n))
    #Ahora quitamos el propio número
    divis.remove(n)
    return sum(divis)

In [31]:
suma_divisores(24)


Out[31]:
36

Los números perfectos entre los 1000 primeos naturales son:


In [32]:
[x for x in range(1,1001) if x == suma_divisores(x)]


Out[32]:
[6, 28, 496]

En total son


In [33]:
len([x for x in range(1,1001) if x == suma_divisores(x)])


Out[33]:
3

Ejercicio 3

Demostremos que si $2^{p} -1 es primo necesariamente p es primo. Vamos a demostrarlo usando el contrarecíproco.

Supongamos que $p$ no es primo. Por tanto lo podemos expresar como producto de dos números. Sean $m,n \in \mathbb{N}$ tal que $2 \le m,n < p$ y $mn=p$. Tenemos que demostar que "Si $p$ no es primo entonces $2^{p}-1$ tampoco es primo".

Sea $p = mn$ para $m,n \in \mathbb{N}$ tales que $2 \le m,n < p$

$2^{mn}-1 = (2^m)^n -1 = (2^m -1 )((2^m)^{n-1} + (2^m)^{n-1} + ... + 2^m + 1)$

por nuestra hipótesis tenemos

$2 \le 2^m -1 < 2^p -1$

Así $2^m -1$ divide a $2^p -1$ y esto nos dice que $2^p -1$ es compuesto.

Hemos demostrado que si p no es primo entonces $2^p -1$ tampoco lo es. Podemos afirmar pues:

Si $2^p -1$ es primo, entonces $p$ es primo.

Sabiendo esto, primero buscamos los primos entre los primeros 257 numeros.


In [34]:
primos_en_258 = []

In [35]:
for i in range(1,258):
    if es_primo(i):
        primos_en_258.append(i)

In [36]:
print(primos_en_258)


[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257]

Como comprobar si un primo de la forma $2^{p} -1$ es una tarea muy pesada cuando p crece vamos a usar el algoritmo de Lucas-Lehmer.


In [37]:
def LucasLehmer(p):
    """
    Este algoritmo determina si 2**p-1 es primo para p >= 2
    """
    if p == 2:
        return True
    
    s = 4
    M = 2**p -1
    for i in range(3, p+1):
        s = (s**2 -2) % M
        
    return s == 0

In [38]:
lista = []
for i in primos_en_258:
    lista.append( (i, LucasLehmer(i) ) )

In [39]:
print(lista)


[(2, True), (3, True), (5, True), (7, True), (11, False), (13, True), (17, True), (19, True), (23, False), (29, False), (31, True), (37, False), (41, False), (43, False), (47, False), (53, False), (59, False), (61, True), (67, False), (71, False), (73, False), (79, False), (83, False), (89, True), (97, False), (101, False), (103, False), (107, True), (109, False), (113, False), (127, True), (131, False), (137, False), (139, False), (149, False), (151, False), (157, False), (163, False), (167, False), (173, False), (179, False), (181, False), (191, False), (193, False), (197, False), (199, False), (211, False), (223, False), (227, False), (229, False), (233, False), (239, False), (241, False), (251, False), (257, False)]

En esta lista tenemos tuplas de los primeros 258 números y si son primos de Mersenne. Los que lo cumplen son


In [40]:
print([x[0] for x in lista if x[1] == True ])


[2, 3, 5, 7, 13, 17, 19, 31, 61, 89, 107, 127]

Luego Mersenne se había equivocado y la lista correcta es la anterior.

Vemos que no es cierto que para todo $p$ primo $2^{p} -1$ sea primo.

Ejercicio 4 La conjetura de Goldbach afirma que todo número natural par mayor que 3 se puede poner como la suma de dos números primos

1. Escribe (1000+2a) como suma de dos primos. Halla todas las descomposiciones posibles de (1000+2a) como suma de dos primos. ¿De cuántas formas se puede descomponer (1000+2*a) como suma de dos primos?.


In [41]:
numero = 1000+2*a
print(numero)


1970

creamos una lista de primos hasta 1000+2a


In [42]:
def lista_primos(n):
    lista = []
    for i in range(1,n+1):
        if es_primo(i):
            lista.append(i)
    
    return lista

In [43]:
print(lista_primos(numero))


[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951]

In [44]:
def suma_primos(numero):
    primos = lista_primos(numero)
    indice_i = 0
    indice_m = len(primos) - 1
    while indice_i <= indice_m:
        suma = primos[indice_i] + primos[indice_m]
        if suma < numero:
            indice_i += 1
        else:
            if suma == numero:
                yield primos[indice_i], primos[indice_m]
            indice_m -= 1

Soluciones:

  • 1000+2a como suma de dos primos

In [45]:
list(suma_primos(numero))[0]


Out[45]:
(19, 1951)
  • Todas las descomposiciones como suma de primos

In [46]:
print(list(suma_primos(numero)))


[(19, 1951), (37, 1933), (97, 1873), (103, 1867), (109, 1861), (139, 1831), (181, 1789), (193, 1777), (211, 1759), (223, 1747), (229, 1741), (271, 1699), (277, 1693), (307, 1663), (313, 1657), (349, 1621), (373, 1597), (421, 1549), (439, 1531), (487, 1483), (499, 1471), (523, 1447), (541, 1429), (547, 1423), (571, 1399), (643, 1327), (673, 1297), (691, 1279), (733, 1237), (739, 1231), (757, 1213), (769, 1201), (853, 1117), (877, 1093), (883, 1087), (907, 1063), (919, 1051), (937, 1033)]
  • Numero de formas

In [47]:
len(list(suma_primos(numero)))


Out[47]:
38

2. Define la función goldbach(n) que devuelva una pareja de primos que sumen n. Define la función goldbachtotal(n) que devuelva la lista de todas las parejas de primos que sumen n. Define dgoldbach(n) que devuelva el número de descomposiciones de Goldbach que admite n.


In [48]:
def golbach(n):
    primos = lista_primos(n)
    sumas = list(suma_primos(n))
    return sumas[0]

In [49]:
golbach(12)


Out[49]:
(5, 7)

In [50]:
def dgoldbach(n):
    primos = lista_primos(n)
    sumas = list(suma_primos(n))
    return len(sumas)

In [51]:
dgoldbach(24)


Out[51]:
3

Ejercicio 5


In [52]:
def ackermann(m, n):
    if m == 0:
        return n+1
    if n == 0:
        return ackermann(m-1, 1)
    return ackermann(m-1, ackermann(m, n-1))

In [53]:
ackermann(3,2)


Out[53]:
29

Al intentar calcular el valor para ackermann(4,2) se desborda la pila por lo que hay que buscar otra manera de resolver el problema.

Propiedades de la función de Ackermann:

  1. A(1, n) = n + 2
  • A(2, n) = 2 n + 3
  • A(3, n) = 2n + 3 - 3
  • A(4, n) = $2^{2^{2^{...}}} − 3$ donde el primer sumando es una potencia anidada de n + 3 niveles.

Así para el caso de ackerman(4,2) el resultado sería


In [54]:
numero = 2
n = 2
for i in range(n+2):
    numero = numero**2
print(numero)


65536

Así Akermann(4,2) = $2^{65536} - 3 $