# TP 03 correction : Fonctions
# BCPST1B 2026-2027
# Lycée Hoche, Versailles
# L.-C. LEFÈVRE

#%% partie I

def somme(x, y):
    print("La somme de", x, "et de", y, "est", x+y)

# test : deux appels de la fonction
somme(3, 4)
somme(-6, 2)

#%%

def moyenne(x, y):
    return (x + y) / 2

m = moyenne(12, 14)
print("La moyenne est", m)
# ceci n'est pas possible si on écrit print((x + y)/2) dans la fonction

#%%

def f():
    print("Cette fonction n'a pas de paramètres ni de valeur de retour.")
    print("Est-elle pour autant utile ?")
    return
    print("Ceci, par contre, ne s'affichera jamais.")

# appel, sans paramètres ni retour
f()

#%%

def divise_proprement(x, y):
    if y == 0:
        print("Il ne faut JAMAIS diviser par 0 !!!")
        return
    return x / y

# deux tests
q = divise_proprement(6, 2)
print("Résultat de 6/2 :", q)
q = divise_proprement(5, 0)
print("Résultat de 5/0 :", q)

#%% exercice 1

def perimetre_rectangle(a, b):
    """ Calcule le périmètre du rectangle de côtés a et b """
    return 2*a + 2*b

# test
print(perimetre_rectangle(3, 5))

#%% exercice 2

def valeur_absolue(x):
    """ Calcule la valeur absolue de x """
    if x >= 0:
        return x
    else:
        return -x

# test
print(valeur_absolue(5))
print(valeur_absolue(-7))

#%% exercice 3

# le plus naïf possible
def maximum(a, b, c):
    """ Calcule le plus grand nombre entre a, b et c """
    if a >= b and a >= c:
        return a
    elif b >= a and b >= c:
        return b
    else:
        return c

# test (attention à bien tester dans chaque situation)
print(maximum(10, 6, 3))
print(maximum(6, 10, 3))
print(maximum(6, 3, 10))
# ce dernier cas risque de ne pas marcher si on utilise des inégalités strictes au lieu de large… on ne serait pas dans le premier cas, ni le deuxième, donc la fonction renvoie c
print(maximum(10, 10, 3))

#%% exercice 4.1

def partie_entiere(x):
    """ Calcule la partie entière de x, ne marche que si x est positif """
    n = 0
    while n <= x:
        n = n + 1
    return n - 1

# test
print(partie_entiere(3.14))
print(partie_entiere(8))

#%% exercice 4.2

def partie_entiere_mieux(x):
    """ Calcule la partie entière de x, aussi bien pour x positif que négatif """
    n = 0
    if x >= 0:
        while n <= x:
            n = n + 1
        return n - 1
    else:
        while n > x:
            n = n - 1
        return n

# test (attention à bien tester tous les cas, x positif ou négatif, entier ou non)
print(partie_entiere_mieux(-3.14))
print(partie_entiere_mieux(-5))

#%% exercice 5

def hein(x):
    """ Calcule la partie entière de la racine carrée de x.
        On cherche le plus grand nombre n tel que son carré soit inférieur ou égal à x. """
    n = 0
    while n**2 <= x:
        n = n + 1
    return n - 1

# test
print(hein(33))

#%% exercice 7

import math

# racine carrée : sqrt(x)
# partie entière : floor(x)

# PGCD : gcd(a, b) (greatest common divisor)
# PPCM : lcm(a, b) (least common multiple)

# floor(x) est le plus grand entier inférieur ou égal à x (« plancher »), c'est bien la fonction mathématique partie entière.
# ceil(x) est le *plus petit* entier *supérieur ou égal* à x (« plafond »), appelé en mathématiques partie entière supérieure.
# int(x) « arrondit vers 0 ». Ce n'est pas la même chose que la partie entière !

print(math.floor(6.3))
print(math.ceil(6.3))
print(int(6.3))

print(math.floor(-6.3))
print(math.ceil(-6.3))
print(int(-6.3))

#%% exercice 8

import math

def f(x):
    y = math.sin(2*math.pi*x)**3 * math.exp(math.sqrt(x))
    return y

# test : comparer avec la calculatrice
print(f(1/4))

#%% exercice 9

from random import randint

def dé():
    x = randint(1, 6)
    return x

# test (relancer plusieurs fois)
print(dé())

#%% exercice 10

from random import randint

def réponse():
    x = randint(1, 4)
    if x == 1:
        return "oui"
    elif x == 2:
        return "non"
    elif x == 3:
        return "peut-être"
    else:
        return "je ne sais pas"

# test
print(réponse())

#%% partie V

def divise_proprement(x, y):
    assert y != 0, "Il ne faut JAMAIS diviser par 0 !!!"
    return x / y

# test invalide
print(divise_proprement(5, 0))

#%% exercice 11

def moyenne_harmonique(x, y):
    assert (x > 0 and y > 0) or (x < 0 and y < 0), "x et y doivent être de même signe et non-nuls, sinon on risque de diviser par zéro et c'est MAL !!!"
    H = 1 / ( (1/x + 1/y) / 2)
    return H

# tests (exécuter les lignes unes par unes)
print(moyenne_harmonique(3, -3))
print(moyenne_harmonique(0, 5))
print(moyenne_harmonique(4, 7))

#%% exercice 12

def seuil(t):
    assert t >= 1, "Sinon ça n'a aucun sens, réfléchi !!!"
    S = 0
    i = 1
    while S < t:
        S = S + 1/i
        i = i + 1
    return i

# test
t = 1
while t <= 20:
    print("dépasse", t, "en", seuil(t), "étapes")
    t = t + 1

#%% exercice 13.1

# version naïve avec boucle while, nous ferons beaucoup mieux après
def est_premier(n):
    assert n >= 0, "n doit être un entier positif"
    if n == 0:
        return False
    elif n == 1:
        return False
    else:
        i = 2
        # continuer tant que n n'est pas divisible par i
        while i < n and n % i != 0:
            i = i + 1
        # on a fini la boucle soit parce que i divise n, soit car i atteint la valeur n
        if i == n:
            return True
        else:
            return False

# test
est_premier(2)
est_premier(4)
est_premier(17)
est_premier(91) # 13 * 7

#%% exercice 13.2

def premiers(n):
    i = 0
    while i <= n:
        if est_premier(i):
            print(i)
        i = i + 1

# test
premiers(100)
