# PREUD'HOMME BONTOUX Geoffrey - PeiP 12 - 2014/2015
# TP n°4 donné le 3/10/2014 - Recherche de zéro par dichotomie
# http://www.fil.univ-lille1.fr/~wegrzyno/portail/Info/Doc/HTML/tp_iteration_conditionnelle.html

import doctest

# [Q1] Définissez en Python la fonction f.
def f(x):
    """
    Renvoie la valeur x**2-3

    CU : x réel positif

    Exemple :
    >>> f(0)
    -3
    >>> f(42)
    1761
    """
    assert((type(x) is int or type(x) is float) and x >= 0), \
        "x doit être un réel positif"

    return x**2-3

# [Q2] Créez deux variables a et b, puis calculez f(a) et f(b)
a = 0
b = 2

f_a = f(a) # -3
f_b = f(b) # 1

# [Q2] Calculez aussi la longueur de l’intervalle [a,b].
intervalle = b-a

# [Q3] Créez une variable c puis calculez f(c).
c = intervalle/2+a # 1
f_c = f(c) # -2

# [Q3] Doit-on chercher le zéro de f dans l’intervalle ]a,c[ ou dans
# l’intervalle ]c,b[ ?

# f(c) vaut -2, donc 0 ∈ [f(c);f(b)], donc on doit chercher le zéro de f dans
# ]c,b[

# [Q4] Écrivez une fonction zero qui prend un paramètre epsilon
# strictement positif et qui renvoie une approximation du zéro de f à epsilon
# / 2 près.
def zero(epsilon):
    """
    Renvoie une approximation du zéro de f à epsilon/2 près.

    CU : epsilon doit être un réel supérieur à 0

    Exemple :
    >>> zero(0.1)
    1.6875
    >>> zero(0.00001)
    1.7320480346679688
    """
    assert((type(epsilon) is int or type(epsilon) is float) and epsilon >= 0), \
        "epsilon supérieur à 0"

    # Pour être conforme à la règle PEP 3104
    mini = a
    maxi = b

    while maxi - mini >= epsilon:
        milieu = (maxi - mini)/2+mini
        if f(milieu) > 0:
            maxi = milieu
        else:
            mini = milieu
    return milieu

# [Q5] Modifiez votre fonction zero pour qu’elle accepte en paramètres
# n’importe quelle fonction continue strictement monotone et n’importe quel
# intervalle initial contenant le zéro de cette fonction.
def fTest(x): # Fonction fournie pour tester zeroGenrique
    """
    Renvoie la valeur x**3-4

    CU : x réel

    Exemple :
    >>> f(0)
    -3
    >>> f(42)
    1761
    """
    assert((type(x) is int or type(x) is float)), \
        "x doit être un réel"

    return x**3-4

def zeroGenerique(fonction, mini, maxi, epsilon):
    """
    Renvoie une approximation du zéro de la fonction f entre mini et maxi
    à epsilon/2 près.

    CU : fonction E → F continue et monotone avec E,F ⊂ ℝ, mini,maxi ∈ E,
    mini<maxi, epsilon réel supérieur à 0

    Exemple :
    >>> zeroGenerique(fTest, -10, 10, 0.001)
    1.5875244140625
    """
    assert(type(mini) is int or type(mini) is float), "mini doit être un réel"
    assert(type(maxi) is int or type(maxi) is float), "maxi doit être un réel"
    assert(mini < maxi), "mini doit être inférieur à maxi"
    assert((type(epsilon) is int or type(epsilon) is float) and epsilon >= 0), \
        "epsilon doit être un réel supérieur à 0"

    while maxi - mini >= epsilon:
        milieu = (maxi - mini)/2+mini
        if fonction(milieu) > 0:
            maxi = milieu
        else:
            mini = milieu
    return milieu

def tester():
    doctest.testmod(verbose=True)