IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

Python paresseux !


Sujet :

Python

  1. #1
    Rédacteur
    Avatar de Zavonen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 772
    Détails du profil
    Informations personnelles :
    Âge : 77
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 772
    Par défaut Python paresseux !
    'Lazzy' est un mot à la mode. La 'lazzy evaluation' c'est 'fashion'.
    Python n'est jamais en retard, en voici la preuve.
    Dans un passé proche on ne disposait pas du type 'rationnel' en standard (il paraît que c'est fait depuis la version 2.6, mais j'attends encore un peu parce que la plupart des biblios sont soit incompatibles soit non à jour quoiqu'on dise...).
    Quoiqu'il en soit j'ai relevé mes manches pour 'palucher' une classe des rationnels.
    Ca donne à peu près ça. Je l'ai fait à l'instinct et par la suite, quand j'ai vu des propositions tierces, elles ressemblaient comme deux gouttes d'eau à la mienne. Comme quoi, dans ce cas d'école il n'y a pas 36 façons de faire. Bref ça donne ça ...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    # -*- coding: utf-8 -*-
    from math import *
     
    # un module de modélisation des nombres rationnels
     
    # pgcd de deux entiers positifs
    #suivant l'algorithme d'Euclide
    def pgcd(x,y):
        if(x==0 or y==0):
            return 1
        if (y%x==0):
            return x
        else:
            return pgcd(y%x,x)
        return
     
    #*****************classe Rationnel*********************************
    class Rationnel:
     
        #simplification des fractions
        def normalise(self):
            g = pgcd(abs(self.num), abs(self.den))
            self.num = self.num / g
            self.den = self.den / g
            if(self.num*self.den<0):
                if self.den<0:
                    self.den=-self.den
                    self.num=-self.num
            else:
                if self.den <0:
                    self.den=-self.den
                    self.num=-self.num
            return
     
        def __init__(self, num, den = 1):  # Constructeur
            if den == 0:
                raise ZeroDivisionError, 'denominateur nul'
            else:
                self.num=num
                self.den=den
                self.normalise()
            return
        #teste si la fraction est entière
        def entier(self):
            return self.num%self.den==0
        #teste si nulle
        def nul (self):
            return self.num==0
     
        """Les opérations binaires"""
        def __add__(self, other): #addition
            n=self.num*other.den+other.num*self.den
            d=self.den*other.den
            return Rationnel(n,d)
        def __rmul__(self,other): #multiplication
            n=self.num*other.num
            d=self.den*other.den
            return Rationnel(n,d)
        def __sub__(self, other): #soustraction
            n=self.num*other.den-other.num*self.den
            d=self.den*other.den
            return Rationnel(n,d)
        def __div__(self,other): #division
            if other.nul():
                raise ZeroDivisionError, 'diviseur nul'
            else:
                n=self.num*other.den
                d=self.den*other.num
                return Rationnel(n,d)
            return
        """opérateurs unaires"""
        def __neg__(self): #opposé
            return Rationnel(-self.num,self.den)
        def __invert__(self):
            if self.nul(): #inverse
                raise ZeroDivisionError, 'diviseur nul'
            else:
                return Rationnel (self.den,self.num)
            return
        def __pow__(self,n):
            if n==0:
                return Rationnel(1,1)
            elif n>0:
                return Rationnel (self.num**n,self.den**n)
            else:
                if self.nul():
                    raise ZeroDivisionError, 'puissance negative d\' nul'
                else:
                    return Rationnel(self.den**(-n),self.num**(-n))
            return
     
        """Les comparaisons"""
        def __eq__(self,other):
           return self.num*other.den==self.den*other.num
        def __lt__(self,other):
            return self.num*other.den<self.den*other.num
        def __le__(self,other):
            return self.num*other.den<=self.den*other.num
        def __gt__(self,other):
            return self.num*other.den>self.den*other.num
        def __ge__(self,other):
            return self.num*other.den>=self.den*other.num
        def __ne__(self,other):
           return self.num*other.den!=self.den*other.num
     
        # pour voir une fraction sur la console appelée par print
        def __str__(self):
            if self.entier():
                return str(self.num)
            else:
                return str(self.num)+'/'+str(self.den)
    #************************fin de la définition**********************
    Il y a une bizarrerie...
    L'opérateur de multiplication est défini par une surcharge de __rmul__ et non de __mul__ (en gros pour ceux qui l'ignorent rmul c'est quand le self est l'opérande de droite.
    Si vous surchargez __mul__ au lieu de __rmul__ cela marche aussi bien.
    Venons en au fait. Mon but est de développer un module d'algèbre linéaire sur le corps Q (c'est d'ailleurs chose faite maintenant).
    Alors à partir du type rationnel il faut développer les vecteurs à composantes rationnelles, les matrices à coeffs rat. etc, etc..
    Commençons par les vecteurs.
    Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    # -*- coding: utf-8 -*-
     
    from rationnels import *
    class VecteurQn:
        """modélisation des vecteurs à n dimensions rationnelles"""
        def __init__(self,L):
            """constructeur"""
            self.V=L
            self.n=len(L)
        def __str__(self):
            """resprésentation externe print, etc..."""
            L=[str(x) for x in self.V]
            return '('+ ",".join(L)+')'
        def nul(self):
            """test de nullité"""
            return all([x.nul() for x in self.V])
        def __add__(self,other):
            """addition des vecteurs"""
            if self.n!=other.n:
                raise 'size: ' 'Tailles non concordantes'
            else:
                L=[self.V[i]+other.V[i] for i in range(0,self.n)]
                return VecteurQn(L)
        def __neg__(self):
            """opposé d'un vecteur"""
            return VecteurQn([-x for x in self.V])
        def __sub__(self,other):
            """différence de deux vecteurs"""
            return self+(-other)
        def __rmul__(self,k):
            """ produit par un scalaire rationnel"""
            L=[k*x for x in self.V]
            return VecteurQn(L)
     
    def main():
        """test de la classe ci-dessus"""
        half=Rationnel(1,2)
        third=Rationnel(1,3)
        one=Rationnel(1)
        L=[one,half, third]
        V1=VecteurQn(L)
        V2=V1
        print V1
        print V2
        print V1+V2
        print -V1
        V3=V1-V2
        print V3
        print V3.nul()
        V4=half*V1
        print V4
        print V4.nul()
        return
     
    if __name__=='__main__':
        main()
    Il faut définir le produit d'un vecteur par un scalaire et là ON N'A PAS LE CHOIX ! c'est bien __rmul__ qu'il faut surcharger.
    Que se passe-t-il si on a surchargé __mul__ dans la classe Rationnel ?
    Si je veux calculer (1/2)V il faudra écrire quelque chose comme :
    Un_demi (bien frais) = Rationnel(1,2)
    W=Un_demi*V
    Et là notre Python paresseux va refuser avec un message abscons.
    La raison !...
    Il veut évaluer un produit a * b où a est rationnel alors il va chercher la surcharge de __mul__ dans la classe correspondante et il trouve que comme le second facteur n'est pas du type rationnel il ne peut pas faire le travail, et puis il va se coucher.
    S'il n'était pas paresseux avant d'abandonner si rapidement il irait jeter un coup d'oeil sur l'opérande de droite et voir que pour sa classe il y a une surcharge de __rmul__.
    Python a encore beaucoup à apprendre de C++, cela ne pourrait arriver en C++ où toutes les possibilités sont testées et les ambiguïtés mise ne relief quand il y en a.
    Est-ce que j'ai bien compris?
    Ce qu'on trouve est plus important que ce qu'on cherche.
    Maths de base pour les nuls (et les autres...)

  2. #2
    Expert confirmé
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 486
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 486
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    Je ne suis pas un grand spécialiste de ces questions, mais il me semble que quand __mul__ ne s'applique pas, il doit renvoyer NotImplemented, et python passe alors la main à __rmul__. Donc, dans ton cas, il faut surcharger les 2 et définir quand l'un ou l'autre s'applique selon le pb que tu veux résoudre.

    http://docs.python.org/reference/dat...object.__mul__

    Tyrtamos

  3. #3
    Rédacteur
    Avatar de Zavonen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 772
    Détails du profil
    Informations personnelles :
    Âge : 77
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 772
    Par défaut
    Merci Tyrtamos pour ta réponse,
    Je vais regarder ça dès que j'ai un moment.
    Ce qu'on trouve est plus important que ce qu'on cherche.
    Maths de base pour les nuls (et les autres...)

  4. #4
    Rédacteur
    Avatar de Zavonen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 772
    Détails du profil
    Informations personnelles :
    Âge : 77
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 772
    Par défaut
    Etonnant !
    J'ai donc surchargé les deux opérateurs __mul__ et __rmul__ dans la classe Rationnel, avec des définitions différentes (juste pour voir).
    Normalement il y a ambiguïté et le compilateur devrait le remarquer, mais non... il prend par défaut la surcharge de __mul__ et pas l'autre.
    Cette remarque est très intéressante mais elle semble confirmer le fait que Python est vraiment suffisamment fainéant pour ne pas aller voir qu'existent des surcharges contradictoires.
    Pour ce qui concerne mon problème cela ne change rien; je suis obligé de surcharger__rmul__ de toutes façons donc la surchage de __mul__ n'apporte rien qu'une complication supplémentaire avec à la clé la certitude d'avoir des bugs dans une version future (4.5 ???) quand notre BDFL se rendra compte qu'il y a là un sérieux problème.
    Ce qu'on trouve est plus important que ce qu'on cherche.
    Maths de base pour les nuls (et les autres...)

  5. #5
    Membre chevronné Avatar de dapounet
    Profil pro
    Étudiant
    Inscrit en
    Juillet 2007
    Messages
    469
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juillet 2007
    Messages : 469
    Par défaut
    Bonjour,

    Citation Envoyé par Zavonen Voir le message
    Etonnant !
    J'ai donc surchargé les deux opérateurs __mul__ et __rmul__ dans la classe Rationnel, avec des définitions différentes (juste pour voir).
    Normalement il y a ambiguïté et le compilateur devrait le remarquer, mais non... il prend par défaut la surcharge de __mul__ et pas l'autre.
    Cette remarque est très intéressante mais elle semble confirmer le fait que Python est vraiment suffisamment fainéant pour ne pas aller voir qu'existent des surcharges contradictoires.
    Pour ce qui concerne mon problème cela ne change rien; je suis obligé de surcharger__rmul__ de toutes façons donc la surchage de __mul__ n'apporte rien qu'une complication supplémentaire avec à la clé la certitude d'avoir des bugs dans une version future (4.5 ???) quand notre BDFL se rendra compte qu'il y a là un sérieux problème.
    Il n'y a pas de surcharge de fonction en Python (quand on redéfinit une fonction, elle écrase simplement la précédente).
    Ce n'est pas peut-être qu'une apparence, mais quand je te lis j'ai l'impression que tu cherches plus à dénigrer Python qu'à résoudre un problème.
    Personnellement je n'ai pas compris ton problème (je ne vois pas le rapport avec l'évaluation paresseuse, par exemple).

  6. #6
    Rédacteur
    Avatar de Zavonen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 772
    Détails du profil
    Informations personnelles :
    Âge : 77
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 772
    Par défaut
    je ne vois pas le rapport avec l'évaluation paresseuse, par exemple
    Il n'y a AUCUN rapport avec l'évaluation paresseuse.
    Et moi je vois qu'on ne rigole pas sur ce forum. J'en tiendrai compte désormais...
    j'ai l'impression que tu cherches plus à dénigrer Python qu'à résoudre un problème
    Si Python ne me plaisait pas, je ne perdrais pas mon temps à pleurnicher ici, je choisirai un autre langage, point final !
    Je CROIS simplement avoir mis le doigt sur une faiblesse du langage (qui a beaucoup plus de qualités que de défauts). Et je demande, à tout hasard, si quelqu'un partage mes conclusions, a rencontré des situations semblebles ou peut me proposer quelque chose de plus propre qu'une solution artificielle consistant à surcharger un opérateur 'cousin'.
    Par ailleurs si tu ne t'étonnes pas que puissent coexister deux surcharges contradictoires, et bien ... tant mieux pour toi.
    Ce qu'on trouve est plus important que ce qu'on cherche.
    Maths de base pour les nuls (et les autres...)

  7. #7
    Membre chevronné Avatar de dapounet
    Profil pro
    Étudiant
    Inscrit en
    Juillet 2007
    Messages
    469
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juillet 2007
    Messages : 469
    Par défaut
    Citation Envoyé par Zavonen Voir le message
    Je CROIS simplement avoir mis le doigt sur une faiblesse du langage (qui a beaucoup plus de qualités que de défauts). Et je demande, à tout hasard, si quelqu'un partage mes conclusions, a rencontré des situations semblebles ou peut me proposer quelque chose de plus propre qu'une solution artificielle consistant à surcharger un opérateur 'cousin'.
    Je voulais parler de cette phrase :

    Citation Envoyé par Zavonen Voir le message
    Pour ce qui concerne mon problème cela ne change rien; je suis obligé de surcharger__rmul__ de toutes façons donc la surchage de __mul__ n'apporte rien qu'une complication supplémentaire avec à la clé la certitude d'avoir des bugs dans une version future (4.5 ???) quand notre BDFL se rendra compte qu'il y a là un sérieux problème.
    Si tu sais que les méthodes fournies par Python ne te suffisent pas et que tu arrives même à prédire l'avenir du langage, je ne vois pas ce qu'on peut t'apporter.


    Citation Envoyé par Zavonen Voir le message
    Par ailleurs si tu ne t'étonnes pas que puissent coexister deux surcharges contradictoires, et bien ... tant mieux pour toi.
    Je n'ai toujours pas compris quel est le problème exact. __rmul__() est appelée seulement quand __mul__() n'est pas disponible. Qu'est-ce qu'il y a de contradictoire à ce que les deux soient définies ? Merci de montrer un code simple qui montre où est le problème.

  8. #8
    Expert confirmé
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 486
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 486
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    Voilà un exemple d'utilisation simplifié.

    Création d'un premier type de nombre: classe nombre1:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     
    class nombre1(object):
     
        def __init__(self, x):
                self.x = x
     
        def __str__(self):
            return "%s" % self.x
     
        def __add__(self,autre):
            return self.__class__(self.x + autre.x)
     
        def __mul__(self,autre):
            if self.x==5:
                return NotImplemented
            else:
                return self.__class__(self.x * autre.x)
     
        def __rmul__(self,autre):
            print "(c'est le __rmul__ de nombre1 qui s'y colle)"
            return self.__class__(autre.x * self.x)
    Création d'un second type de nombre: classe nombre2:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     
    class nombre2(object):
     
        def __init__(self, x):
                self.x = x
     
        def __str__(self):
            return "%s" % self.x
     
        def __add__(self,autre):
            return self.__class__(self.x + autre.x)
     
        def __mul__(self,autre):
            if self.x==5:
                return NotImplemented
            else:
                return self.__class__(self.x * autre.x)
     
        def __rmul__(self,autre):
            print "(c'est le __rmul__ de nombre2 qui s'y colle)"
            return self.__class__(autre.x * self.x)
    Dans les 2 cas, j'ai implémenté __mul__, mais j'ai interdit l'opération lorsque le 1er terme de la multiplication est "5". Dans ce cas, __mul__ renvoie NotImplemented (qui est un objet de base comme None).

    Regardons ce qui se passe:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    x = nombre1(6)
    y = nombre2(7)
    print x*y
    42
    Là, ça marche normalement, et c'est le __mul__ de nombre1 qui a fonctionné.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    x = nombre1(5)
    y = nombre2(7)
    print x*y
    (c'est le __rmul__ de nombre2 qui s'y colle)
    35
    Là, le __mul__ de nombre1 ayant détecté que le 1er facteur est "5" interdit l'opération et renvoie NotImplemented. De ce fait, l'interpréteur python essaye le __rmul__ de nombre2 et l'opération réussit.

    Je ne sais pas si ça colle à ton problème, mais en tout cas, c'est conforme à la notice, et ça marche.

    Extrait de la notice concernant les méthodes __rxxx__:

    These functions are only called if the left operand does not support the corresponding operation and the operands are of different types.3.3 For instance, to evaluate the expression x-y, where y is an instance of a class that has an __rsub__() method, y.__rsub__(x) is called if x.__sub__(y) returns NotImplemented.
    Tyrtamos

  9. #9
    Rédacteur
    Avatar de Zavonen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 772
    Détails du profil
    Informations personnelles :
    Âge : 77
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 772
    Par défaut
    @tyrtamos
    Ton exemple a l'air fort complet et très intéressant.
    Je crois bien qu'il m'apporte le 'pourquoi' des choses (c'est bien ce qui m'intéressait).
    Dès que j'ai un moment je regarde ça à la loupe.
    Merci pour le temps passé.
    PS: Voilà, j'ai trouvé le temps (ce sujet m'intéresse). Si je veux n'utiliser que des __mul__ Dans mon problème, il faut que dans la surchage de __mul__ sur la classe des rationnels je commence par faire un test sur le type du second opérande et renvoyer NotImplemented si ce n'est pas lui-même un rationnel. Dans ce cas, si l'opérande de droite est un vecteur c'est le rmul de sa classe qui va s'y coller automatiquement.
    De fait, je suis venu à Python après une longue pratique de langages à typage fort où tu n'as pas ce problème puisque pour chaque surcharge du même opérateur tu précises le type du second opérande.Merci
    Ce qu'on trouve est plus important que ce qu'on cherche.
    Maths de base pour les nuls (et les autres...)

  10. #10
    Membre confirmé Avatar de arnaudk
    Inscrit en
    Février 2009
    Messages
    38
    Détails du profil
    Informations forums :
    Inscription : Février 2009
    Messages : 38
    Par défaut
    J'ai suivi le post avec intérêt car je suis également en train de redéfinir certaines classes algébriques. Par contre j'ai été paresseux , et me base sur la 2.6 pour surcharger le module fraction. Je ne suis pas allé aussi loin que Zavonen, mais je vais me manifester si je suis face aux même comportements des opérandes ( pour l'instant cela n'a pas été le cas ).

    Je prévois de faire des classes du même type également pour les puissances entières, les équations du 1er et 2nd degré, les racines, et le calcul littéral.

    J'ai toutefois une question d'optimisation pour Zavonen : tu calcules le pgcd par récursivité, et je le fais à l'aide d'une boucle while, on utilise tous deux l'algorithme d'Euclide.
    Y a-t-il des différences notables de rapidité entre ces deux méthodes ?

  11. #11
    Rédacteur

    Avatar de Matthieu Brucher
    Profil pro
    Développeur HPC
    Inscrit en
    Juillet 2005
    Messages
    9 810
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur HPC
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Par défaut
    Citation Envoyé par Zavonen Voir le message
    Je CROIS simplement avoir mis le doigt sur une faiblesse du langage (qui a beaucoup plus de qualités que de défauts). Et je demande, à tout hasard, si quelqu'un partage mes conclusions, a rencontré des situations semblebles ou peut me proposer quelque chose de plus propre qu'une solution artificielle consistant à surcharger un opérateur 'cousin'.
    Effectivement, ça peut être problématique si on ne fait pas attention quand on crée des classes qui travaillent ensemble ou sur des opérations mathématiques.

  12. #12
    Rédacteur
    Avatar de Zavonen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 772
    Détails du profil
    Informations personnelles :
    Âge : 77
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 772
    Par défaut
    J'ai suivi le post avec intérêt car je suis également en train de redéfinir certaines classes algébriques. Par contre j'ai été paresseux , et me base sur la 2.6 pour surcharger le module fraction. Je ne suis pas allé aussi loin que Zavonen, mais je vais me manifester si je suis face aux même comportements des opérandes ( pour l'instant cela n'a pas été le cas ).
    Objectivement, moi aussi je suis paresseux (c'est une qualité intellectuelle), simplement j'ai commencé avec 2.51 et il y a des dépendances. un jour je reprendrai le tout.
    Je développe parallèlement une algèbre linéaire sur les corps Z/pZ. Tout comme Q l'intérêt de ces corps est que les calculs sont 'exacts' un déterminant qui doit être nul EST nul, avec scipy.linalg il vaut 1.25647e-16
    Si tu as des problèmes de ce type, welcome sur le forum.
    C'est en exposant ces problèmes qu'on fait avancer les choses.
    Ce qu'on trouve est plus important que ce qu'on cherche.
    Maths de base pour les nuls (et les autres...)

  13. #13
    Rédacteur
    Avatar de Zavonen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 772
    Détails du profil
    Informations personnelles :
    Âge : 77
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 772
    Par défaut
    J'ai toutefois une question d'optimisation pour Zavonen : tu calcules le pgcd par récursivité, et je le fais à l'aide d'une boucle while, on utilise tous deux l'algorithme d'Euclide.
    Y a-t-il des différences notables de rapidité entre ces deux méthodes ?
    C'est vrai il n'y a pas d'optimisation, je rédige un document pédagogique, je n'ai pas de gros calculs à faire, je cherche une lisibilité maximum avant une efficacité maximum (je ne sais pas si la récursivité est un bon choix...). Du point de vue des perfs il n'y a pas photo l'itératif est toujours meilleur. D'ailleurs si on cherche de bons algos pour des calculs de pgcd on trouve mieux qu'Euclide (j'ai vu ça il y fort longtemps).
    Ce qu'on trouve est plus important que ce qu'on cherche.
    Maths de base pour les nuls (et les autres...)

  14. #14
    Rédacteur
    Avatar de Zavonen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 772
    Détails du profil
    Informations personnelles :
    Âge : 77
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 772
    Par défaut
    Effectivement, ça peut être problématique si on ne fait pas attention quand on crée des classes qui travaillent ensemble ou sur des opérations mathématiques.
    Et oui .. Moralité: tout se paye. Python est conçu de telle sorte qu'on puisse écrire très vite des choses qui fonctionnent et que tout le monde peut comprendre, mais l'absence de typage (et 3.0 n'y changera rien) provoque des problèmes qu'ignorent des programmes plus lourds rédigés dans un procédural quelconque.
    J'attends encore un peu pour voir s'il y a quelques réactions et puis je ferme la discussion.
    Ce qu'on trouve est plus important que ce qu'on cherche.
    Maths de base pour les nuls (et les autres...)

  15. #15
    Rédacteur

    Avatar de Matthieu Brucher
    Profil pro
    Développeur HPC
    Inscrit en
    Juillet 2005
    Messages
    9 810
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur HPC
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Par défaut
    Citation Envoyé par Zavonen Voir le message
    J'attends encore un peu pour voir s'il y a quelques réactions et puis je ferme la discussion.
    Pourquoi la fermer ??

  16. #16
    Rédacteur
    Avatar de Zavonen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 772
    Détails du profil
    Informations personnelles :
    Âge : 77
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 772
    Par défaut
    Je voulais dire je place le tag 'résolu', mais c'est vrai cela ne la ferme pas, je me suis mal exprimé.
    Ce qu'on trouve est plus important que ce qu'on cherche.
    Maths de base pour les nuls (et les autres...)

  17. #17
    Expert confirmé
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 486
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 486
    Billets dans le blog
    6
    Par défaut
    @Zavonen:

    Si tu cherches à faire des calculs numériques "exacts", pense au module "decimal" qui définit des nombres décimaux sans limite de taille et sans les erreurs des flottants (0.1 fait vraiment 0.1 et pas 0.10000000000000001). On peut faire avec, des choses impressionnantes.

    Mon intérêt pour le sujet du topic vient du fait que j'essaye de faire des nb complexes qui utilisent les nombres de ce module. Et je commence en ce moment par créer toute la bibliothèque des fonctions transcendantes qui n'existe pas avec ce module. Je peux déjà, par exemple, trouver les 1000 premières décimales de pi en moins de 6 secondes (en passant par les arc tangentes - formule de Machin). Et calculer le sinus ou le cosinus d'un angle avec 50 chiffres en 6/1000 de secondes en calculant les séries... (mais ne me demandez pas à quoi ça sert...).

    Quand aux programmes de type factorielle ou PGCD, je privilégie systématiquement les versions itératives. Elles sont en général plus rapides, et échappent aux limites de la pile dont la récursion a besoin (env. 1000). Or, l'un des avantages de Python pour les calculs arithmétiques, c'est l'utilisation intégrée des entiers longs, également sans limite de taille. Par exemple, la factorielle de 20000 est calculée facilement en moins de 4 secondes, et donne un nombre de 77338 chiffres. Inutile de dire que la version récursive serait dans les choux...

    Tyrtamos

  18. #18
    Membre confirmé Avatar de arnaudk
    Inscrit en
    Février 2009
    Messages
    38
    Détails du profil
    Informations forums :
    Inscription : Février 2009
    Messages : 38
    Par défaut
    Citation Envoyé par Zavonen Voir le message
    Je développe parallèlement une algèbre linéaire sur les corps Z/pZ. Tout comme Q l'intérêt de ces corps est que les calculs sont 'exacts' un déterminant qui doit être nul EST nul, avec scipy.linalg il vaut 1.25647e-16
    Si tu as des problèmes de ce type, welcome sur le forum.
    C'est en exposant ces problèmes qu'on fait avancer les choses.
    Effectivement.
    Même si apparemment nous sommes quelques-uns à retravailler les mêmes notions, je ne sais pas si on les bosse dans la même direction : mon objectif avec ces classes n'est pas un calcul exact, mais un affichage détaillé des calculs, en vue de la génération d'exercices pour collège et lycée.
    Donc les valeurs en jeu ne risquent pas de fortement ralentir le programme.

    Je serais en tout cas curieux de voir le résultat de ton document pédagogique et de ta classe sur Fp, vu que j'enseigne python au lycée, et je préfère comparer/apprendre des progressions des autres.

    Merci à vous deux pour la comparaison itération/récursivité, voilà une question de résolue pour moi

  19. #19
    Rédacteur
    Avatar de Zavonen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 772
    Détails du profil
    Informations personnelles :
    Âge : 77
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 772
    Par défaut
    Or, l'un des avantages de Python pour les calculs arithmétiques, c'est l'utilisation intégrée des entiers longs, également sans limite de taille.
    C'est grâce à cela qu'on peut développer une classe de rationnels sans se soucier des débordements.
    pense au module "decimal" qui définit des nombres décimaux sans limite de taille et sans les erreurs des flottants (0.1 fait vraiment 0.1 et pas 0.10000000000000001).
    Cela je m'en sert déjà pour des exemples de calculs avec précision (almost unlimited ...).
    Je donne d'ailleurs un exemple dans mon cours.
    http://gilles-dubois.developpez.com/...els/index.html
    Choisir le titre représentation en machine. dans ce module j'ai introduit une conversion des rationnels en décimaux python, puis je calcule le nombre d'Euler comme somme des inverses factorielles avec 50 décimales.
    Ce qu'on trouve est plus important que ce qu'on cherche.
    Maths de base pour les nuls (et les autres...)

  20. #20
    Rédacteur
    Avatar de Zavonen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 772
    Détails du profil
    Informations personnelles :
    Âge : 77
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 772
    Par défaut
    Je serais en tout cas curieux de voir le résultat de ton document pédagogique et de ta classe sur Fp, vu que j'enseigne python au lycée, et je préfère comparer/apprendre des progressions des autres.
    L'existant est ici:
    http://gilles-dubois.developpez.com/Maths/
    Le module d'algèbre linéaire devrait être raccordé au menu principal fin juin si tout va bien.
    Si tu veux un avant-goût:
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    """Modélisation des corps Z/pZ avec p premier"""
     
    def GenZp(p):
        """génère la classe paramétrée Z/pZ"""
        class C(object):
            car=p
            def __init__(self,m):
                """initialisation à partir d'un entier"""
                self.n=m%self.car
            def __str__(self):
                """représentation externe pour print etc..."""
                return str(self.n)
            def nul(self):
                """test de nullité"""
                return self.n==0
            ### les opérateurs unaires
            def __neg__(self):
                """opposé"""
                return C(-self.n)
            def __invert__(self):
                """inverse"""
                if not self.nul():
                    y=1
                    while (self.n*y)%self.car != 1:
                        y+=1
                return C(y)
            ### les opérations binaires
            def __add__(self,other):
                """addition"""
                return C(self.n+other.n)
            def __mul__(self,other):
                """multiplication"""
                return C(self.n*other.n)
            def __sub__(self,other):
                """soustraction"""
                return C(self.n-other.n)
            def __div__(self,other):
                return self*~(other)
            def __pow__(self,k):
                """puissances"""
                if k >=0:
                    return C(self.n**k)
                else:
                    return ~self**(-k)
        return C
     
    #diverses fonctions de test
    def TableAddition(K):
        """comme son nom l'indique"""
        for x in K:
            for y in K:
                print x+y,
            print
    def TableMultiplication(K):
        """comme son nom l'indique"""
        for x in K:
            for y in K:
                print x*y,
            print
    def TableSoustraction(K):
        """comme son nom l'indique"""
        for x in K:
            for y in K:
                print x-y,
            print
    def TableDivision(K):
        """comme son nom l'indique"""
        for x in K:
            for y in K:
                if not y.nul():
                    print x/y,
            print        
    def Opposes(K):
        """Les opposés"""
        for x in K:
            print -x,
        print
     
    def Inverses(K):
        """Les inverses"""
        for x in K:
            if not x.nul():
                print ~x,
        print
     
    def Puissances(x):
        """les puissances"""
        for n in range(-5,5):
            print x**n,
        print
     
    def Test(k):
        """appelle les test un par un"""
        C=GenZp(k)
        K=[C(i) for i in range(0,k)]
        Opposes(K)
        print '-----------------'
        Inverses(K)
        print '-----------------'    
        TableAddition(K)
        print '-----------------'
        TableMultiplication(K)
        print '-----------------'
        TableSoustraction(K)
        print '-----------------'
        TableDivision(K)
        print '-----------------'
        Puissances(K[2])
        print '-----------------'        
     
    def main():
        """fonction principal - appelle les tests globaux"""
        Test(5)
        Test(7)
     
    if __name__=='__main__':
        main()
    Ce qu'on trouve est plus important que ce qu'on cherche.
    Maths de base pour les nuls (et les autres...)

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [langage] traduction d'un fonction python en perl
    Par ay_pepito dans le forum Langage
    Réponses: 3
    Dernier message: 04/12/2007, 15h06
  2. CORBA & PYTHON
    Par stan91stan dans le forum CORBA
    Réponses: 5
    Dernier message: 10/06/2004, 12h32
  3. module .so pour python... ?!
    Par totoetlititi dans le forum Langages de programmation
    Réponses: 2
    Dernier message: 09/03/2004, 14h51
  4. [Lien]erreur dans mon programme python
    Par durnambule dans le forum Général Python
    Réponses: 11
    Dernier message: 29/01/2004, 14h59

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo