import time as time#Permet de calculer la durée d'un calcul (optionnel)

print("EXERCICE 1")

a=10
b=5
a=a+b#Donc a=15, on change la valeur de a mais pas celle de b
b=a+b#Donc b=15+5=20, on change la valeur de b mais pas celle de a
b=a#Donc b=15, on change la valeur de b mais pas celle de a
b=2*b#Donc b=2*15=30, on change la valeur de b mais pas celle de a
print("Normalement, b vaudrait 30, vérifions-le: b=",b)
print("Normalement, a vaudrait 15, vérifions-le: a=",a)

print("EXERCICE 2")

a=12
b=5
print("Au départ, la valeur de a est ",a)
print("Au départ, la valeur de b est ",b)

#Attention le code
#b=a
#a=b
#Ne fonctionne pas, en effet, à la ligne 22, b va prendre va prendre 
#la valeur de a, c'est-à-dire 12, puis à la ligne 23, a va prendre la 
#valeur de b, c'est-à-dire 12

c=b#On sauvegarde l'ancienne valeur de b
b=a#b prend l'ancienne valeur de a
a=c#a prend l'ancienne valeur de b (qui a été stocké grÃ¢ce à c)

print("Maintenant, la nouvelle valeur de a est ",a)
print("Maintenant, la nouvelle valeur de b est ",b)

print("EXERCICE 3")
def FonctionMystere(a,b,c):
    """Cette fonction renvoie la moyenne des trois nombres a, b et c"""
    s=a+b+c
    m=s/3
    return m
#Il faut bien comprendre qu'à ce moment-là, nous n'avons fait que 
#définir la fonction, mais cela ne fait pour l'instant aucun calcul
#Il faut donc appeler la fonction en indiquant des valeurs a,b et c:
    
res=FonctionMystere(5,10,9)#Calcule le résultat retourné par la fonction
#mystère et stocke ce résultat dans une variable appelée res
print(res)#Affiche la valeur de la variable res

print("EXERCICE 4")

def MaFonctionValeurAbsolue(x):
    """Cette fonction renvoie la valeur absolue d'un réel x"""
    if x>=0:
        return x
    if x<0:#À la place de if x<0:, on aurait pu mettre un else:
        return -x
    
print("La valeur absolue de 3 vaut ",MaFonctionValeurAbsolue(3))
print("La valeur absolue de -4 vaut ",MaFonctionValeurAbsolue(-4))

print("EXERCICE 5")

def SuisJePair(n):
    """
    Cette fonction, renvoie True ssi n est pair. Pour cela, on teste le reste 
    de la division euclidienne de n par 2. RAPPEL: la division euclidienne:
    soit deux entiers a et b, il existe un unique couple d'entiers (q,r)  
    tel que a=bq+r avec 0<=r<b, q se calcule par q=a//b et r par r=a%b
    """
    if n%2==0:#Alors n=2q+r avec r=0 donc n est pair
        return True
    if n%2==1:#Alors n=2q+r avec r=1 donc n est impair
        return False
    
print("3 est pair ?", SuisJePair(3))#Devrait renvoyer False
print("8 est pair ?", SuisJePair(8))#Devrait renvoyer True
print("-8 est pair ?", SuisJePair(-8))#Devrait renvoyer True

print("EXERCICE 6")

def MaFonctionTrinome(a,b,c):
    """
    Pour l'équation ax^2+bx+c=0 renvoie le nombre de solutions réelles.
    Et le cas échant ces solutions réelles.
    """
    if a!=0:
        Delta=b*b-4*a*c
        if Delta>0:
            return 2,(-b+Delta**0.5)/(2*a),(-b-Delta**0.5)/(2*a)
        if Delta==0:
            return 1,-b/(2*a)
        if Delta<0:
            return 0
    if a==0:#Cas où on n'a pas une équation du second degré
        print("Ce n'est pas une équation du 2nd degré, idiot!")
        
print(MaFonctionTrinome(1,0,-9))
print(MaFonctionTrinome(1,0,1))
print(MaFonctionTrinome(0,2,1))
        
print("EXERCICE 7")

S=0
n=100
for i in range(n+1):#Attention il faut mettre n+1 pour que le dernier i valle n
    S=S+i#À chaque étape on rajoute i: avant S=0+1+2+3+...+i-1
    #Maintenant il vaut S=(0+1+2+3+...i-1)+i
print("La boucle for donne 0+1+2+3+...+100 = ",S)
print("Les maths donne 0+1+2+3+...+n=n(n+1)/2=5050 avec n=100")

print("EXERCICE 8")

def Suite(n):
    """
    Renvoie le terme d'indice n de la suite u_{n+1}=2u_n+3
    """
    un=2#u_0=2
    for i in range(n):
        # un=u_i
        un=2*un+3 #Maintenant u_n=2*u_i+3=u_{i+1}
    return un

print("u_{100} = ",Suite(100))

print("EXERCICE 9")

x=182
compteur=0
while x>=5:
    x=x/5
    compteur=compteur+1
print(x)
print(compteur)

print("EXERCICE 10")

def S(n):
    """
    Pour un entier n, renvoie n//2 quand n est pair, 3*n+1 sinon
    """
    if n%2==0:#Teste si n est pair
        return n//2#le n//2 permet d'être certain que le résultat est un entier
    #Si on met n/2, alors cela sera considéré comme un nombre à virgule
    if n%2==1:
        return 3*n+1
    
def TempsDeVol(n):
    """
    É‰tant donné un entier n, calcule et renvoie le nombre d'étapes
    nécessaire pour retomber sur 1, 2 ou 4
    """
    A=n#On stocke dans A les différentes valeurs de la suite
    compteur=0#Variable: qui va compter combien de fois il faut
    #calculer S(A) avant d'arriver sur 1, 2 ou 4
    while A!=4 and A!=2 and A!=1:#A va s'arrÃªter s'il vaut 4 ou 2 ou 1
        A=S(A)#On calcule le terme d'après
        compteur=compteur+1#On incrémente la variable compteur de 1
    return compteur#On renvoie le compteur

AttentePourDix=TempsDeVol(10)#On appelle la fonction TempsDeVol avec n=10
print("Le temps de vol pour 10 est", AttentePourDix)

def TempsDeVolMaxi(n):
    """
    Renvoie la liste des entiers naturels dont le temps de vol 
    a été maximum parmi tous les nombres entre 3 et n
    """
    Tmax=TempsDeVol(1)#Calcul du temps de vol
    L=[1]#Liste des entiers ayant un TempsDeVol égal à Tmax
    for k in range(4,n+1):#Pour tous les entiers k entre 4 et n
        T=TempsDeVol(k)#On calcul le temps de vol de k
        if T==Tmax:#S'il atteint le max en cours
            L.append(k)#Alors on le rajoute à la liste des éléments qui 
            #atteignent ce max
        if T>Tmax:#S'il est strictement plus grand que le max
            Tmax=T#Alors on actualise la valeur maximum
            L=[k]#On stock l'élément qui atteint ce max        
    return Tmax,L

tic=time.time()#On retient le temps du début du calcul
Tmax,L=TempsDeVolMaxi(10**6)
print("Le temps de vol maximum est",Tmax, "et a été atteint",len(L)," fois avec",L)
tac=time.time()#On retient le temps à la fin du calcul
print("Le temps de ce calcul a duré", tac-tic,"secondes")

print("EXERCICE 11")

def DivisionEuclidienne(a,b):
    r=a
    q=0
    while r>b:#Tant que r est plus grand que b
        r=r-b#On retire b à r
        q=q+1#On rajoute 1 à q
    return q,r#On renvoie q et r une fois la boucle while terminée

a=51
b=4
quotient,reste=DivisionEuclidienne(51,4)
print("Le reste de la division euclidienne de",a,"par",b,"est",reste)
print("Le quotient de la division euclidienne de",a,"par",b,"est",quotient)

print("EXERCICE 12")

L=[2,3,8,2]
def AfficherListe(L):
    """
    É‰tant donnée, une liste L, cette fonction affiche successivement
    tous les éléments de cette liste
    """
    for i in range(len(L)):
        print(L[i])#L[i] est le i-ème élément de la liste, on l'affiche

AfficherListe(L)

print("EXERCICE 13")

def SommeListe(L):
    """
    É‰tant donnée une liste L, cette fonction calcule la somme de tous
    les éléments de cette liste.
    """
    S=0#Variable de départ
    for i in range(len(L)):
        S=S+L[i]
    #for element in L: #méthode alternative
        #S=S+element
    return S#attention le return S ne doit pas être indenté car il n'est pas
    #dans la boucle, en effet c'est une fois la boucle for terminée que S
    #prend la valeur attendue

Somme=SommeListe([2,3,8,-10])#On exécute la fonction avec une liste
print("La somme des termes de la liste",L,"vaut",Somme)

print("EXERCICE 14")
#(3,4,5) est un triplet Pythagoricien, en effet, 3*3+4*4=25=5*5
tic=time.time()
L=[]
for c in range(1,1001):#c varie entre 1 et 1000
    for b in range(1,c):# b varie entre 1 et c-1
        for a in range(1,b+1):#a varie entre 1 et b
            if c*c==a*a+b*b:#Si on a l'égalité
                L.append((a,b,c))#On rajoute à L le triplet (a,b,c)
tac=time.time()
print("On a trouvé",len(L),"triplets pythagoricien")
print("Le temps de ce calcul a duré", tac-tic,"secondes")