programme python

Bonjour
Je ne comprends pas pourquoi le programme ci-dessous me renvoie une erreur dès que n>10.
Pourriez-vous m'expliquer. Merci d'avance.
from math import *

def distance(x1,y1,x2,y2):
    return sqrt((x1-x2)**2 + (y1-y2)**2)

def longueurCourbe(f,a,b,n):
    longueur = 0
    x1,y1 = a,f(a)
    h = (b-a)/n
    for i in range(n):
        x2 = x1 + h
        y2 = f(x2)
        longueur = longueur + distance(x1,y1,x2,y2)
        x1,y1 = x2,y2
    return longueur

l=2*longueurCourbe(lambda x: sqrt(1-x**2),0,1,10)
print(l)

Réponses

  • Bonjour,

    D'abord, tu pourrais présenter ton code correctement, avec les indentations.
    Ensuite, quand tu fais x2=x1+h, le dernier déborde de l'intervalle de définition de ta fonction, il est supérieur à 1.

    Cordialement,

    Rescassol
  • J'ai laissé l'indentation. Je ne comprends pas.
    Pourquoi le dernier déborde ? Si c'était le cas le problème se poserait pour toutes les valeurs de n, non ? je n'ai pas compris.
  • Es-tu sûr de pouvoir calculer toutes les images que tu donnes à manger à f ?
    Algebraic symbols are used when you do not know what you are talking about.
            -- Schnoebelen, Philippe
  • En passant ton code (indenté) avec n=20 et en ajoutant une commande l.n(), j'obtiens
    2*sqrt(1/10) + 2*sqrt(1/400*(sqrt(399) - 6*sqrt(11))^2 + 1/400) + 2*sqrt(1/400*(sqrt(399) - 20)^2 + 1/400) + 2*sqrt(1/400*(sqrt(391) - 6*sqrt(11))^2 + 1/400) + 2*sqrt(1/400*(sqrt(391) - 8*sqrt(6))^2 + 1/400) + 2*sqrt(1/400*(sqrt(319) - 4*sqrt(21))^2 + 1/400) + 2*sqrt(1/400*(sqrt(319) - 10*sqrt(3))^2 + 1/400) + 2*sqrt(1/400*(sqrt(231) - 2*sqrt(51))^2 + 1/400) + 2*sqrt(1/400*(sqrt(231) - 16)^2 + 1/400) + 2*sqrt(1/400*(sqrt(111) - 2*sqrt(19))^2 + 1/400) + 2*sqrt(1/400*(sqrt(111) - 12)^2 + 1/400) + 2*sqrt(1/400*(2*sqrt(91) - 3*sqrt(39))^2 + 1/400) + 2*sqrt(1/400*(2*sqrt(91) - 5*sqrt(15))^2 + 1/400) + 2*sqrt(1/400*(2*sqrt(51) - 5*sqrt(7))^2 + 1/400) + 2*sqrt(1/400*(3*sqrt(39) - 4*sqrt(21))^2 + 1/400) + 2*sqrt(1/400*(sqrt(39) - 2*sqrt(19))^2 + 1/400) + 2*sqrt(1/400*(3*sqrt(31) - 10*sqrt(3))^2 + 1/400) + 2*sqrt(1/400*(3*sqrt(31) - 16)^2 + 1/400) + 2*sqrt(1/400*(5*sqrt(15) - 8*sqrt(6))^2 + 1/400) + 2*sqrt(1/400*(5*sqrt(7) - 12)^2 + 1/400)
    
    3.13830041990457
    
  • Merci pour vos réponses. Qu'est ce qu'une commande l.n() ? De mon côté quand je mets 20, ça me retourne une erreur.
  • Quelle erreur ?
    J'utilise en fait Sagemath.
  • Je vois deux problèmes.

    Le premier problème, c'est que la dernière valeur de x2 dépasse parfois la valeur $1$ à cause d'erreurs d'arrondi. C'est ce qu'ont déjà dit Rescassol et Foys. Dans ce cas très précis, on peut remplacer la définition de x2 par
    x2 = min(x1+h,b)
    
    Au fait, il peut y avoir des erreurs d'arrondi avec des nombres décimaux, par exemple $n=100$, parce que 1./100 ne vaut pas $0.01$ mais un nombre dyadique (de la forme $n/2^k$, $n$ et $k$ entiers) qui est une approximation de $0.01$. Apparemment, $100$ fois ce nombre, ce n'est pas le flottant 1., c'est un peu plus que 1. (ça fait une erreur). En revanche, pas d'erreur avec $n=128$ ou $n=1024$.


    Le deuxième problème, c'est que la fonction renvoie toujours zéro, c'est déplaisant. Cela vient du type des nombres manipulés : par défaut, des entiers. Dans le calcul de $h=(b-a)/n$, l'opération en jeu est une division euclidienne entre entiers et pas une division de flottants. Par conséquent, la variable h est l'entier nul.

    Pour faire fonctionner le code, il suffit de changer la définition de h en :
    h = 1.*(b-a)/n
    
    ce qui force une conversion en flottants et donne un résultat significatif ($3.132$, à peu près la même chose que trouve GaBuZoMeu).

    NB 1 : Cela marche aussi directement si on calcule
    l=2*longueurCourbe(lambda x: sqrt(1-x**2),0,1.,10)
    
    mais bien sûr c'est moins propre / fiable.

    NB 2 : Si le calcul fonctionne en l'état avec Sage, c'est parce que Sage calcule dans le corps des rationnels. Autrement dit, pour Sage, $(1-0)/10$ vaut bien $1/10$ et pas zéro et le dernier x2 calculé vaut précisément $1$ et pas plus. Mais Python n'a pas de type "rationnel" par défaut.
  • Merci beaucoup pour ces explications très claires ! En modifiant la définition de h, j'obtiens toujours une erreur dans le code précédent.
    J'ai testé un autre programme qui lui ne me retourne pas d'erreurs. Les valeurs obtenues diffèrent toutefois un peu de celles obtenues avec le programme précédent. J'ai un peu de mal à comprendre pourquoi celui-ci fonctionne et l'autre non.
    from math import*
    def distance(x1,y1,x2,y2):
        return(sqrt((x1-x2)**2+(y1-y2)**2))
        
    def longueurCourbe(f,a,b,n):
        s=0
        for i in range(n):
            x1=a+i*(b-a)/n
            x2=a+(i+1)*(b-a)/n
            y1=f(x1)
            y2=f(x2)
            s=s+distance(x1,y1,x2,y2)
        return(s)
    
    l=2*longueurCourbe(lambda x:sqrt(1-x**2),0,1,1000000)
    print(l)
    
  • Il faudrait que quelqu'un previenne les auteurs du document eduscol de rajouter une remarque.
    Heureusement, le probleme ne se pose pas avec le code Xcas correspondant de notre document ressource lycee, je rajoute quand meme une remarque.
  • Oui effectivement je testais les programmes python du nouveau doc d'accompagnement.
  • Si si ça dépend bien de la version de Python utilisée. En python 3 une division d'entiers renvoie un flottant. Il faut utiliser le double slash pour avoir une division entière.
  • Ce que j'ai appelé plus haut « deuxième problème » n'a pas lieu d'être en Python 3, qui se comporte différemment de Python 2 :
    ~$ python
    Python 2.7.12 (default, Nov 19 2016, 06:48:10) 
    [GCC 5.4.0 20160609] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> 1/3
    0
    >>> quit()
    
    ~$ python3
    Python 3.5.2 (default, Nov 17 2016, 17:05:23) 
    [GCC 5.4.0 20160609] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> 1/3
    0.3333333333333333
    >>> quit()
    ~$ 
    

    Sinon, avec les définitions suivantes, je n'ai pas d'erreur (Python 2 ou 3) :
    from math import sqrt
    
    def distance(x1,y1,x2,y2):
        return(sqrt((x1-x2)**2+(y1-y2)**2))
    
    def L(f,a,b,n):
        longueur = 0
        x1,y1 = a,f(a)
        h = 1.*(b-a)/n
        print(h)
        for i in range(n):
            x2 = min(x1 + h,b)
            y2 = f(x2)
            longueur = longueur + distance(x1,y1,x2,y2)
            x1,y1 = x2,y2
        return longueur
    
    f = lambda x: sqrt(1-x**2)
    
    L(f,0,1,1000000)
    

    Edit : Déjà dit par remark et skyffer3 (mais sans l'exemple). Je ne sais pas quelle version « les jeunes » utilisent. Par défaut, avec Ubuntu, "python" lance Python 2 et "python3" Python 3.
Connectez-vous ou Inscrivez-vous pour répondre.