L1 = [1,2,3,3,4,5]      # pour tester les fonctions des exercices
L2 = [-0.34, 4.5, 7, 9, -3.14, 3, 7]


## Exercice 1

def moyenne(L) :
    n = len(L)
    somme = 0
    for x in L :
        somme = somme + x
    moyenne = somme/n
    return moyenne
    
def ecartQuadratiqueMoyen(L) :
    n = len(L)
    somme = 0
    m = moyenne(L)
    for x in L :
        somme = somme + (x-m)**2
    ecartQM = somme/n
    return ecartQM

def minListe(L) :
    min = L[0]
    for x in L :
        if min > x :
            min = x
    return min
    
def maxListe(L) :
    max = L[0]
    for x in L :
        if max < x :
            max = x
    return max
    
def estPresent(x, L) :
    for e in L :
        if x == e :
            return True
    return False

def nombreFoisPresent(x, L) :
    nombre = 0
    for e in L :
        if e == x :
            nombre += 1
    return nombre

        
## Exercice 2

def somme(n) :
    if n > 0 :
        S = 0
        for i in range(1,n+1) :  # pour i allant de 1 à n 
            S = S+i
        return S
    else :
        return None
   
    
def factorielle(n) :
    if (n == 0) or (n == 1) :
        return 1
    else :
        i=1
        fact = 1
        while i <= n :
            fact = fact*i
            i += 1
        return fact
        
def produitPairs(n) :
    if n > 0 :
        i = 1
        produit = 1
        while i <= n :
            if i%2 == 0 :  # i est pair
                produit = produit*i
            i += 1
        return produit
    else :
        return None # On l'écrit mais en cas d'ommission Python le met d'office
    

def estPremier(n) :
    assert n > 0
    if n == 1 :
        return False
    else :
        i=2
        while i < n :
            if n%i == 0 : # n est divisible par i
                return False
            i += 1
        return True
        
        
## Exercice 3

def sommeRiemann() :
    n = 1
    S = 0
    while (1/n**2 > 1e-10) :
        S += 1/n**2
        n += 1
    return S
    
## Exercice 4

# Version 1 : on fait le produit sur un nombre fini N de termes

def wallis1() :
    produit = 1
    N = 10000
    for i in range(1,N+1) :
        produit = produit*4*i*i/(4*i*i-1)
    resultat  = 2*produit
    return resultat
    
# Version 2 : on convient d'une précision sur les termes du produit.

def wallis2() :
    i = 1
    produit = 1
    precision = 1e-10
    while 1/(4*i*i-1) > precision :   # c'est l'écart 4i**2/(4i**2-1) - 1
        produit = produit*4*i*i/(4*i*i-1)
        i += 1
    resultat  = 2*produit
    return resultat

## Exercice 5

def affichage_jhms(duree) :
    L = []               # liste des résultats
    dureeJour = 24*3600  # durée d'un jour en secondes
    dureeHeure = 3600    # durée d'une heure en secondes
    dureeMinute = 60     # durée d'une minute en secondes
    
    nbreJour = duree//dureeJour
    L.append(nbreJour)
    duree = duree % dureeJour # reste de la div euclidienne
    
    nbreHeures = duree//dureeHeure
    L.append(nbreHeures)
    duree = duree % dureeHeure # reste de la div euclidienne
    
    nbreMinutes = duree//dureeMinute
    L.append(nbreMinutes)
    duree = duree % dureeMinute # reste de la div euclidienne
    
    L.append(duree)  # on ajoute à L les secondes qui restent
    return L

    
## Exercice 6    

# Version 1 : sans utiliser une liste

def u_itera1(n) :
    if n == 0 :
        return 2
    else :
        u = 2       # Initialisation : u0 = 2
        i = 1
        while i <= n :
            u = 3*u-1
            i += 1
        return u

# Version 2 : en utilisant une liste

def u_itera1(n) :
    if n == 0 :
        return 2
    else :
        L = (n+1)*[0]  # Liste contenant u0, u1, ..., un
        L[0] = 2       # Initialisation : u0 = 2
        for i in range(1,n+1) : # pour i allant de 1 à n
            L[i] = 3*L[i-1]-1
        return L[n]
        
# Version récursive
        
def u_rec(n) :
    if n == 0 :  # cas terminal en début de fonction
        u = 2
    else :
        u = 3*u_rec(n-1)-1
    return u

## Exercice 7

def somme_itera(n) :
    S = 0
    for k in range(1,n+1) :   # Pour k allant de 1 à n
        S = S + 1/(k*(k+1))
    return S
    
# La programmation récursive s'appuie sur le fait que 
# S(n) = S(n-1) + 1/( n*(n+1) )

def somme_rec(n) :
    if n == 1 :   # Placer cas terminal en début de fonction
        return 0.5
    else :
        s = 1/(n*(n+1)) + somme_rec(n-1)
        return s

## Exercice 8 Suite de Fibonacci

# On peut utiliser une liste pour gérer la récurrence.
# Cela donne un programme plus lisible

def fibo_itera2(n) :
    if n == 0 :
        return 0           
    elif n == 1 :
        return 1
    else :
        L = (n+1)*[0]      # liste contenant u0, u1, ..., un
        L[0], L[1] = 0,1   # initialisation 
        for i in range(2, n+1) :  # Pour i allant de 2 à n
            L[i] = L[i-1] + L[i-2]           
    return u

# Version récursive

cmpt = 0     # Compteur, défini comme une variable globale

def fibo_rec(n) :
    global cmpt  # indique à la fonction que cmpt est une variable globale
    cmpt += 1    # chaque appel de fibo_rec augmente cmpt de 1
    
    if n == 0 :
        return 0
    elif n == 1 :
        return 1
    else :
        u = fibo_rec(n-1) + fibo_rec(n-2)
    return u

# Le problème de fibo_rec est sa complexité exponentielle
