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

Langage Delphi Discussion :

Additions avec + de 20 chiffres significatifs avec une fonction en Asm à optimiser


Sujet :

Langage Delphi

  1. #1
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 263
    Points
    3 263
    Par défaut Additions avec + de 20 chiffres significatifs avec une fonction en Asm à optimiser
    Bonjour

    Pour faire des additions avec plus de 20 chiffres significatifs sans être pénalisé par des lenteurs je souhaite faire en Asm une fonction à laquelle je donne en entrée deux chaînes-numériques de longueur non limitée et qui renvoie le résultat de l’addition sous forme d’une autre chaîne dont les caractères numériques sont obtenus comme on apprend à l’école dans le style « 8 + 9 = JePose 7 et JeRetiens 1 ». A cet effet les chaînes envoyées en entrée sont des chaînes calibrées de même longueur et commençant par au moins un ‘0’ (ou davantage s’il faut ajuster l’une à l’autre).

    Bien que je sois nul en Asm j’ai réussi à bidouiller une fonction qui réalise ce résultat très très maladroitement avec un fonction que j’aimerais donc optimiser sous plusieurs aspects :
    - extension aux calculs sur des chaines-numériques du type String ou Pchar (au lieu des ShortString’s)
    - soulagement des calculs par des précalculs résumés dans les deux tableaux suivants :

    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
     
    type   TTabPoseRetiens = array['0'..'9','0'..'9'] of Char;
     
    const  AdditionJePose : TTabPR = 
    (('0','1','2','3','4','5','6','7','8','9'),
    ('1','2','3','4','5','6','7','8','9','0'),
    ('2','3','4','5','6','7','8','9','0','1'),
    ('3','4','5','6','7','8','9','0','1','2'),
    ('4','5','6','7','8','9','0','1','2','3'),
    ('5','6','7','8','9','0','1','2','3','4'),
    ('6','7','8','9','0','1','2','3','4','5'),
    ('7','8','9','0','1','2','3','4','5','6'),
    ('8','9','0','1','2','3','4','5','6','7'),
    ('9','0','1','2','3','4','5','6','7','8'))
     
    const AdditionJeRetiens : TTabPR =
    (('0','0','0','0','0','0','0','0','0','0'),
    ('0','0','0','0','0','0','0','0','0','1'),
    ('0','0','0','0','0','0','0','0','1','1'),
    ('0','0','0','0','0','0','0','1','1','1'),
    ('0','0','0','0','0','0','1','1','1','1'),
    ('0','0','0','0','0','1','1','1','1','1'),
    ('0','0','0','0','1','1','1','1','1','1'),
    ('0','0','0','1','1','1','1','1','1','1'),
    ('0','0','1','1','1','1','1','1','1','1'),
    ('0','1','1','1','1','1','1','1','1','1'))
    La fonction Asm à optimiser :
    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
     
    function  AdditionAsm(str1,str2 : shortString; Len : Integer) : shortString;
    //        str1 et str2 en entrée : de même longueur avec mini un 0 au début
    //        str1     = '09123457891235469785743258714586027895'
    //        str2     = '01234568524563759158521739582461397461'
    //        Resultat = '10358026415799228944264998297047425356'
    var       Pose,Retiens : byte; Res : shortString;
    begin     Retiens:=0; Res:=StringOfChar(' ',Len);
      asm     PUSHFD
              PUSHAD
     
              PUSH  ESI
              PUSH  EDX
              PUSH  EDI
              PUSH  ECX
     
              LEA   ESI, str1  // source
              LEA   EDX, str2  // 2ème source
              LEA   EDI, res   // destination
     
              STD   // incrémenter de la fin vers le début
              ADD   ESI, Len  // Initialisation à l'offset de
              ADD   EDI, Len  // début des chaînes + Len
              ADD   EDX, Len  // idem
              MOV   ECX, Len
     
    @Boucle:
              LODSB                    // Calcul de Pose:="s1[i] + s2[i] + retenue"
              MOV   Pose,AL            // caractère de str1
              MOV   AH,Retiens
              ADD   Pose,Ah
              MOV   AH, Byte ptr[EDX]  // caractère de str2
              ADD   Pose,AH
              SUB   Pose,96
              CMP   Pose,10
              JB   @Inf
              SUB   Pose,10
              MOV   AL,Pose
              MOV   Retiens,1          //retenue = 1
              JMP  @Suite
     
    @Inf:     MOV   AL,Pose
              MOV   Retiens,0          //retenue = 0
     
    @Suite:   ADD   AL,48
              DEC   EDX                //caractère précédent de str2
              STOSB
              LOOP @Boucle
     
    @Sors:    POP   ECX
              POP   EDI
              POP   EDX
              POP   ESI
     
              POPAD
              POPFD
    end; //asm
              //res:=trim(res);
              Result:=res;
    end; // AdditionAsm
    Ayant testé les performances de rapidité des fonctions utilisées par la calculatrice-pour-grands-nombres proposée dans les codes-source il s’avère que celles-ci sont fortement sanctionnées dans le cas d’appels répétitifs dans des boucles du fait de la lenteur des conversions des chaînes-numériques vers des Array Of Int64 et réciproquement, inutile donc de me proposer ce type de solution (qui reste néanmoins valable pour une calculatrice utilisée hors boucle)

    Par contre si quelqu’un a de bonnes idées pour rectifier le code de la fonction ci-dessus en Asm cela m’enlèverait une épine du pied et peut-être que d’autres seraient également intéressés par la fonction rectifiée.

    Merci par avance.
    A+
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  2. #2
    Membre éprouvé
    Avatar de CapJack
    Homme Profil pro
    Prof, développeur amateur vaguement éclairé...
    Inscrit en
    Mars 2004
    Messages
    624
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Prof, développeur amateur vaguement éclairé...
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2004
    Messages : 624
    Points : 988
    Points
    988
    Par défaut
    Tu n'utilises pas la bonne démarche : les processeurs de la famille x86 ont depuis toujours un jeu d'instructions arithmétiques BCD (Binary Coded Decimal), parfaitement adapté à ce genre d'opérations. Tu devrais te renseigner sur ce jeu d'instructions.

  3. #3
    Membre éprouvé

    Profil pro
    Inscrit en
    Mai 2003
    Messages
    582
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Mai 2003
    Messages : 582
    Points : 915
    Points
    915
    Par défaut
    bon déjà ca c'est mieux que le code ASM, sans limite aux niveaux des
    strings en entrée et c'est très rapide sur les CPU d'aujourd'hui avec cache etc.
    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
     
    function Addition(const s1:string;const s2:String;Len:integer):string;
    var
      i:integer;
      t:integer;
      r:integer;
    begin
      result:=StringOfChar(' ',Len);
      r:=0;
      for i:=len downto 1 do
      begin
        t:=byte(S1[i])+byte(S2[i])+r;
        if t>=106 then
        begin
          r:=1;
          result[i]:=char(t-58);
        end
        else
        begin
          r:=0;
          result[i]:=char(t-48);
        end;
      end;
    end;
    Si tu tien à utilisé des tableaux pré calculé, je te propose plutot ceci
    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
     
    //0+0=48+48=96
    //9+9=57+57=114 (+1) pour la retenue= 115
    const PreCalcResult : Array [0..115] of char =
    ('0','0','0','0','0','0','0','0','0','0'
    ,'0','0','0','0','0','0','0','0','0','0'
    ,'0','0','0','0','0','0','0','0','0','0'
    ,'0','0','0','0','0','0','0','0','0','0'
    ,'0','0','0','0','0','0','0','0','0','0'
    ,'0','0','0','0','0','0','0','0','0','0'
    ,'0','0','0','0','0','0','0','0','0','0'
    ,'0','0','0','0','0','0','0','0','0','0'
    ,'0','0','0','0','0','0','0','0','0','0'
    ,'0','0','0','0','0','0',{96}'0','1','2','3'
    ,'4','5','6','7','8','9','0','1','2','3'
    ,'4','5','6','7','8','9');
     
    const PreCalcRet : Array [0..115] of Integer =
    (0,0,0,0,0,0,0,0,0,0
    ,0,0,0,0,0,0,0,0,0,0
    ,0,0,0,0,0,0,0,0,0,0
    ,0,0,0,0,0,0,0,0,0,0
    ,0,0,0,0,0,0,0,0,0,0
    ,0,0,0,0,0,0,0,0,0,0
    ,0,0,0,0,0,0,0,0,0,0
    ,0,0,0,0,0,0,0,0,0,0
    ,0,0,0,0,0,0,0,0,0,0
    ,0,0,0,0,0,0,{96}0,0,0,0
    ,0,0,0,0,0,0,1,1,1,1
    ,1,1,1,1,1,1);
     
    function Addition2(const s1:string;const s2:String;Len:integer):string;
    var
      i:integer;
      retenue:integer;
    begin
      result:=StringOfChar(' ',Len);
      retenue:=0;
      for i:=len downto 1 do
      begin
        result[i]:=PreCalcResult[byte(S1[i])+byte(S2[i])+retenue];
        retenue:=PreCalcRet[byte(S1[i])+byte(S2[i])+retenue];
      end;
    end;
    Il n'y a selon moi pas beacoup de gain à utiliser la 2ème solution...
    pour test en entrée
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    const
     str1 = '09123457891235469785743258714586027895';
     str2 = '01234568524563759158521739582461397461';
     
    Const
      NbrCall = 100000;
    ca donne:
    Addition Asm-----0.31 secondes
    Addition Delphi---0.23 secondes
    Addition2 Delphi--0.22 secondes

    En faite, pourquoi en ASM?
    Comment dupliquer un disque...ça vous intéresse?
    Tutoriel et code source delphi ici

  4. #4
    Membre éprouvé

    Profil pro
    Inscrit en
    Mai 2003
    Messages
    582
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Mai 2003
    Messages : 582
    Points : 915
    Points
    915
    Par défaut
    si j'allonge les chaines en entrée, ca devient plus évident que la 2ème est plus rapide...
    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
     
    function Addition2(const s1:string;const s2:String;Len:integer):string;
    var
      i:integer;
      retenue:integer;
      offset:integer;
    begin
      result:=StringOfChar(' ',Len);
      retenue:=0;
      for i:=len downto 1 do
      begin
        offset:=integer(S1[i])+integer(S2[i])+retenue;
        result[i]:=PreCalcResult[offset];
        retenue:=PreCalcRet[offset];
      end;
    end;
    Toujours pour NbrCall = 100000;

    Longueur de chaine:228
    Addition Asm-----0.67 secondes
    Addition Delphi---0.45 secondes
    Addition2 Delphi--0.33 secondes

    Longueur de chaine:11400
    Addition Asm-----n/a (Out of range)
    Addition Delphi---15.72 secondes
    Addition2 Delphi--12.60 secondes
    Comment dupliquer un disque...ça vous intéresse?
    Tutoriel et code source delphi ici

  5. #5
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 263
    Points
    3 263
    Par défaut
    Bonjour,

    A CapJack :

    Tu n'utilises pas la bonne démarche : les processeurs de la famille x86 ont depuis toujours un jeu d'instructions arithmétiques BCD (Binary Coded Decimal), parfaitement adapté à ce genre d'opérations. Tu devrais te renseigner sur ce jeu d'instructions.
    Merci pour cette info : j'ai passé la matinée à fouiller Internet sur les instructions arithmétiques BCD j'en ai pris une migraine mais c'est bien instructif sans toutefois savoir par quel bout je pourrais démarrer.

    Au fait quand j'ai vu que tu étais le premier à répondre je m'attendais à une proposition similaire à la function CJ9 que tu avais créée récemment en Asm pour convertir des chaînes accentuées en majuscules non accentuées à partir de la constante tableau de conversion. J'ai essayé de m'en inspirer mais comme je suis nul en Asm je n'ai pas abouti et la fonction AdditionAsm que j'ai bidouillée n'a marché qu'après de nombreux tâtonnements et ça doit sauter aux yeux d'un connaisseur.

    A Eric Boisvert :

    A) / message de 12h26

    Merci mille fois pour tes codes c'est vraiment sympa.

    En faite, pourquoi en ASM?
    ... tout simplement parceque dans le cadre d'une autre discussion qui portait sur l'optimisation de l'enlèvement d'accents sur des chaînes CapJack avait crée en Asm la fonction CJ9 précitée et qui lorsqu'elle était utilisée dans certaines conditions était nettement plus rapide que sa version homologue basée sur l'utilisation de PChar.
    Const
    NbrCall = 100000;
    ca donne:
    Addition Asm-----0.31 secondes
    Addition Delphi---0.23 secondes
    Addition2 Delphi--0.22 secondes
    ... bigre, les codes en Delphi sont nettement plus rapides qu'en Asm !
    ... d'une certaine façon ça m'arrange de pouvoir coder en Delphi car après l'addition, faudra que je fasse la soustraction, la multiplication, etc
    ... l'objectif de ma demande concernant l'addition étant surtout de commencer sur la meilleure piste.
    ... vu les temps d'exécution obtenus je vais me jeter à mon tour sur des tests comparatifs.

    B) / message de 13h04

    Dis donc t'est bien rapide, j'ai pas eu le temps de terminer ma réponse à ton 1er message que je découvre ton 2ème

    Toujours pour NbrCall = 100000;

    Longueur de chaine:228
    Addition Asm-----0.67 secondes
    Addition Delphi---0.45 secondes
    Addition2 Delphi--0.33 secondes

    Longueur de chaine:11400
    Addition Asm-----n/a (Out of range)
    Addition Delphi---15.72 secondes
    Addition2 Delphi--12.60 secondes
    ... cette fois çi cela devient clair qu'Addition2 est plus rapide.

    En tous cas merci. Je vais me lancer dans les tests.

    A+
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  6. #6
    Membre éprouvé

    Profil pro
    Inscrit en
    Mai 2003
    Messages
    582
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Mai 2003
    Messages : 582
    Points : 915
    Points
    915
    Par défaut
    Peut-être que c'est pas de mes affaires...mais par curiosité....
    à quoi ca peut bien servir? des additions,soustraction de nombre tel que
    1 000 000 000 000 000 000 000
    Si c'est des $...humm, tu m'engage j'espère!
    Comment dupliquer un disque...ça vous intéresse?
    Tutoriel et code source delphi ici

  7. #7
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    488
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 488
    Points : 397
    Points
    397
    Par défaut
    Citation Envoyé par Eric Boisvert
    Si c'est des $...humm, tu m'engage j'espère!
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    v := Addition2('7', '5', 1);
    writeln(v); // -> 2
    Euh, moi je ne t'engage pas

  8. #8
    Membre éprouvé

    Profil pro
    Inscrit en
    Mai 2003
    Messages
    582
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Mai 2003
    Messages : 582
    Points : 915
    Points
    915
    Par défaut
    Faut rester dans le cahier de charge...
    Citation Envoyé par Gilbert Geyer
    A cet effet les chaînes envoyées en entrée sont des chaînes calibrées de même longueur et commençant par au moins un ‘0’
    alors
    Addition2('07', '05', 2)='12'
    Comment dupliquer un disque...ça vous intéresse?
    Tutoriel et code source delphi ici

  9. #9
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 263
    Points
    3 263
    Par défaut
    A Eric Boisvert :
    Peut-être que c'est pas de mes affaires...mais par curiosité....
    à quoi ca peut bien servir? des additions,soustraction de nombre tel que
    1 000 000 000 000 000 000 000
    ... ça va me servir pour améliorer le code d'une appli que j'ai faite pour la résolution d'équations polynômiales à coefficients réels ou complexes de degré N. Actuellement cette appli marche à peu près jusqu'au degé 14 mais quand je cherche les racines de l'équation de degré 15 dont les racines sont la suite des nombres de 1 à 15 les résultats sont faussés du fait des calculs effectués sur seulement 19 à 20 chiffres significatifs.

    Si c'est des $...humm, tu m'engage j'espère!
    ... j'aimerais bien que ce soient des dollards et dans ce cas je t'engagerais volontiers mais dommage ce ne sont que des valeurs numériques.

    Au fait j'ai pu améliorer un peu la rapidité de ta function Addition2 comme suit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    function Addition2EBVbis(const s1,s2 : String; Len : integer) : string;
    var      i, retenue, offset : integer; p : PChar;
    begin    result:=StringOfChar(' ',Len);
             retenue:=0;
             p:=@Result[Len];
             for i:=len downto 1 do
             begin offset:=integer(S1[i])+integer(S2[i])+retenue;
                   //result[i]:=PreCalcResult[offset];
                   p^:=PreCalcResult[offset];
                   retenue:=PreCalcRet[offset];
                   dec(p);
             end;
    end;
    Résultats de mes tests avec Pentium III 1,13 GHz et pour pour NbrCall = 100000 avec additions de chaines-numériques de 128 caractères chacune :
    - Addition2 version originale : mis 271 ms
    - Addition2 version bis : mis 175 ms soit environ 1,5 fois plus speedy.
    Autre résultats avec Addition2 version bis et NbrCall = 100000 :
    - mis 242 ms pour chaines de 228 caractères
    - mis 7953 ms pour chaines de 11400 caractères.

    A Sovitec :
    Rassure toi j'ai vérifié l'exactitude des résultats du calcul à l'aide de la calculatrice pour grands nombres dont le code figure parmi les codes-source du site Devellopez.com que j'ai cité vers la fin de mon premier message.

    ... les chaînes envoyées en entrée sont des chaînes calibrées de même longueur et commençant par au moins un ‘0’
    ... pour l'instant, faute de mieux j'utilise cette astuce pour simplifier les réflexions et le code et pour prévoir une case pour le report de la dernière retenue.

    A+
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  10. #10
    Expert confirmé
    Avatar de anapurna
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2002
    Messages
    3 419
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 419
    Points : 5 818
    Points
    5 818
    Par défaut
    salut


    vous pourriez pas simplifier les tableaux
    actuellement vous ecrivez :

    const PreCalcResult : Array [0..115] of char =
    ('0','0','0','0','0','0','0','0','0','0'
    ,'0','0','0','0','0','0','0','0','0','0'
    ,'0','0','0','0','0','0','0','0','0','0'
    ,'0','0','0','0','0','0','0','0','0','0'
    ,'0','0','0','0','0','0','0','0','0','0'
    ,'0','0','0','0','0','0','0','0','0','0'
    ,'0','0','0','0','0','0','0','0','0','0'
    ,'0','0','0','0','0','0','0','0','0','0'
    ,'0','0','0','0','0','0','0','0','0','0'
    ,'0','0','0','0','0','0',{96}'0','1','2','3'
    ,'4','5','6','7','8','9','0','1','2','3'
    ,'4','5','6','7','8','9');

    const PreCalcRet : Array [0..115] of Integer =
    (0,0,0,0,0,0,0,0,0,0
    ,0,0,0,0,0,0,0,0,0,0
    ,0,0,0,0,0,0,0,0,0,0
    ,0,0,0,0,0,0,0,0,0,0
    ,0,0,0,0,0,0,0,0,0,0
    ,0,0,0,0,0,0,0,0,0,0
    ,0,0,0,0,0,0,0,0,0,0
    ,0,0,0,0,0,0,0,0,0,0
    ,0,0,0,0,0,0,0,0,0,0
    ,0,0,0,0,0,0,{96}0,0,0,0
    ,0,0,0,0,0,0,1,1,1,1
    ,1,1,1,1,1,1);

    pour simplifier on pourrai ecrire ceci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    const PreCalcResult : Array [96..115] of char =
    ({96}'0','1','2','3'
    ,'4','5','6','7','8','9','0','1','2','3'
    ,'4','5','6','7','8','9');
     
    const PreCalcRet : Array [96..115] of Integer =
    ({96}0,0,0,0
    ,0,0,0,0,0,0,1,1,1,1
    ,1,1,1,1,1,1);
    @+ Phil
    Nous souhaitons la vérité et nous trouvons qu'incertitude. [...]
    Nous sommes incapables de ne pas souhaiter la vérité et le bonheur, et sommes incapables ni de certitude ni de bonheur.
    Blaise Pascal
    PS : n'oubliez pas le tag

  11. #11
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 263
    Points
    3 263
    Par défaut
    A Anapurna :

    Salut

    Simplification des tableaux : Pourquoi pas. Je vais essayer pour voir ce que ça donne et si cela n'oblige pas à modifier le code dans un sens qui ralentirait la vitesse d'exécution.

    A+
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  12. #12
    Expert confirmé
    Avatar de anapurna
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2002
    Messages
    3 419
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 419
    Points : 5 818
    Points
    5 818
    Par défaut
    salut

    la modification du code ne doit pas etre compliqué a faire

    par contre je ne sais pas comment delphi gere les indice de tableaux
    donc si il y'a une perte de temps pour l'acces a l'indice

    @+ Phil

    PS : au pire tu peut indicé ton tableau de 0..19
    et enlever a l'offset 96

    @+ phil
    Nous souhaitons la vérité et nous trouvons qu'incertitude. [...]
    Nous sommes incapables de ne pas souhaiter la vérité et le bonheur, et sommes incapables ni de certitude ni de bonheur.
    Blaise Pascal
    PS : n'oubliez pas le tag

  13. #13
    Membre éprouvé

    Profil pro
    Inscrit en
    Mai 2003
    Messages
    582
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Mai 2003
    Messages : 582
    Points : 915
    Points
    915
    Par défaut
    ce qui serait avantagueux aussi...
    ce serait d'envoyer la réponse via la string 2 et on
    tourne le tout en procedure...
    ca permet à delphi d'être encore plus performant en maintenant
    la plupart des variables dans les registres du CPU....
    en plus, on évite l'allocation mémoire à chaque fois pour la réponse...
    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
     
    //=== ATTENTION, S2 sera replacé par la réponse.... ===
    procedure AdditionProc(Const s1:string; var s2: String; Len: integer);
    Var i, retenue, offset: integer; p1,p2: PChar;
    Begin
      retenue := 0;
      p1:= @s1[Len];
      p2 := @s2[Len];
      For i := len Downto 1 Do
      Begin
        offset := integer(p1^) + integer(p2^) + retenue;
                   //result[i]:=PreCalcResult[offset];
        p2^ := PreCalcResult[offset];
        retenue := PreCalcRet[offset];
        dec(p1);
        dec(p2);
      End;
    End;
    c'est encore plus rapide cependant pour le benchmark, faut oublier
    le résultat qui n'est valide que lors du premier apele....
    ca me donne c'est chiffre (pour comparaison)
    Addition2-10.64 secondes
    Addition2EBVbis--6.94 secondes
    AdditionProc--3.78 secondes

    Reste à voir si ca pose un problème de détruire une des string source?
    Comment dupliquer un disque...ça vous intéresse?
    Tutoriel et code source delphi ici

  14. #14
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 263
    Points
    3 263
    Par défaut
    A Anapurna

    la modification du code ne doit pas etre compliqué a faire

    par contre je ne sais pas comment delphi gere les indice de tableaux
    donc si il y'a une perte de temps pour l'acces a l'indice
    ... j'ai pas encore fait l'essai, mais toutes les idées sont bonnes à essayer
    ... et comme tes tableaux sont plus courts ça ira peut-être dans le sens d'un gain de rapidité si ce gain n'est pas contrarié par les modifs du code.
    De toutes façons je placerais le résultat final de la discussion en fin de discussion car il y aura peut-être encore d'autres idées à venir.

    ... et justement je vois qu'Eric Boisvert vient d'intercaler un nouveau message.

    A+
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  15. #15
    Expert confirmé
    Avatar de anapurna
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2002
    Messages
    3 419
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 419
    Points : 5 818
    Points
    5 818
    Par défaut
    salut

    un truc dans ce genre la ?

    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
     
    procedure AdditionProc(Const s1: pchar; s2: pchar;out s3 : String; Len: integer);
    Var i, retenue, offset: integer; p3: PChar;
    Begin
      retenue := 0;
      p3:= @s3[Len];
      For i := len Downto 1 Do
      Begin
        offset := integer(s1^) + integer(s2^) + retenue;
        p3^ := PreCalcResult[offset];
        retenue := PreCalcRet[offset];
        dec(s1);
        dec(s2);
        dec(p3);
      End;
    End;
    @+ Phil

    PS : argh un message qui c'est intercale
    Nous souhaitons la vérité et nous trouvons qu'incertitude. [...]
    Nous sommes incapables de ne pas souhaiter la vérité et le bonheur, et sommes incapables ni de certitude ni de bonheur.
    Blaise Pascal
    PS : n'oubliez pas le tag

  16. #16
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 263
    Points
    3 263
    Par défaut
    A Eric Boisvert :

    Pour la rapidité AdditionProc est effectivement encore 2 fois plus rapide.
    Pour ce qui est du problème de détruire une des string source je vais voir s'il n'y a pas une parade pour contourner le problème.
    Autrement dit voir si le fait de faire une copie préalable de s2 ne ralentit pas trop la performance.
    En tous cas merci pour cette proposition supplémentaire.

    ... ça chauffe : j'ai pas terminé ce message qu'Anapurna a intercalé son message.

    A+
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  17. #17
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 263
    Points
    3 263
    Par défaut
    A Anapurna :

    A première vue ta procedure AdditionProc(Const s1: pchar; s2: pchar;out s3 : String; Len: integer) semble résoudre le problème soulevé par Eric Boisvert concernant la destruction d'une des chaines originales tout en conservant l'intérêt de remplacer la version fonction par une version procedure.
    Du coup j'aurai de quoi faire plein de tests comparatifs demain matin (je suis scotché devant mon micro depuis ce matin).

    Merci pour cette proposition supplémentaire

    A+
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  18. #18
    Expert éminent sénior

    Avatar de sjrd
    Homme Profil pro
    Directeur de projet
    Inscrit en
    Juin 2004
    Messages
    4 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : Suisse

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2004
    Messages : 4 517
    Points : 10 154
    Points
    10 154
    Par défaut
    Un paramètre string en out c'est comme un résultat de fonction : c'est toujours vide (chaîne vide) au début de l'exécution de la routine.
    Donc ce n'est pas mieux que la "version procédure".

    Déjà vous devriez remplacer StringOfChar par SetLength, ça serait déjà ça de pris :
    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
    function Addition(const Val1, Val2 : string) : string;
    const
      WatchReport = Ord('5') + Ord('5');
    var Len, I : integer;
        Report : boolean;
        Val : Byte;
    begin
      Len := Length(Val1);
      SetLength(Result, Len);
     
      Report := False;
      for I := Len downto 1 do
      begin
        Val := Ord(Val1[i]) + Ord(Val2[i]) + Byte(Report);
        Report := Val >= WatchReport;
        if Report then
          dec(Val, 48)
        else
          dec(Val, 58);
        Result[i] := Chr(Val);
      end;
    end;
    sjrd, ancien rédacteur/modérateur Delphi.
    Auteur de Scala.js, le compilateur de Scala vers JavaScript, et directeur technique du Scala Center à l'EPFL.
    Découvrez Mes tutoriels.

  19. #19
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 263
    Points
    3 263
    Par défaut
    A Sjrd :

    Un paramètre string en out c'est comme un résultat de fonction : c'est toujours vide (chaîne vide) au début de l'exécution de la routine.
    Donc ce n'est pas mieux que la "version procédure".
    ... string en out vide au début : merci c'est certainement la raison pour laquelle la dernière proposition d'Anapurna m'envoie un message d'erreur je vais voir pour la rectifier.

    A propos de la nouvelle proposition function Addition(const Val1, Val2 : string) : string avec WatchReport : Merci beaucoup je la copie pour mes tests de demain matin.

    A+
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  20. #20
    Membre éprouvé

    Profil pro
    Inscrit en
    Mai 2003
    Messages
    582
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Mai 2003
    Messages : 582
    Points : 915
    Points
    915
    Par défaut
    Citation Envoyé par Gilbert Geyer
    Pour la rapidité AdditionProc est effectivement encore 2 fois plus rapide.
    ouin.. désolé mais mon benchmark n'était pas correct....

    j'aivais comparé ceci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
      For i := 0 To NbrCall Do
      begin
        srep:=Addition2EBVbis(s1, s2, len);
      end;
    avec ceci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
      For i := 0 To NbrCall Do
      begin
        AdditionProc(s1, s2, len);
      end;
    fallait plutot comparer avec:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
      For i := 0 To NbrCall Do
      begin
        AdditionProc(s1, s2, len);
        srep:=s2;
      end;
    donc, nous avons effectivement un petit gain tout de même grace à SJR
    en remplacant StringOfChar par SetLength.
    La plus rapide demeure donc celle-ci avec les Array Simplifiés par anapurna (J'ignore comment fait delphi... mais ca change pas grand chose pour la vitesse et c'est plus jolie!)
    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
     
    const PreCalcResult : Array [96..115] of char =
    ({96}'0','1','2','3'
    ,'4','5','6','7','8','9','0','1','2','3'
    ,'4','5','6','7','8','9');
     
    const PreCalcRet : Array [96..115] of Integer =
    ({96}0,0,0,0
    ,0,0,0,0,0,0,1,1,1,1
    ,1,1,1,1,1,1);
     
    Function Addition2EBVbis(Const s1: String; Const s2: String; Len: Cardinal): String;
    Var
      i: Cardinal;
      retenue: Cardinal;
      offset: Cardinal;
      p:PChar;
    Begin
      SetLength(result,len);
      p:=@Result[len];
      retenue := 0;
      For i := len Downto 1 Do
      Begin
        offset := integer(S1[i]) + integer(S2[i]) + retenue;
        P^ := PreCalcResult[offset];
        retenue := PreCalcRet[offset];
        dec(p);
      End;
    End;
    maintenant les chiffres....
    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
     
    Longueur de chaine:11400
    NbrCall = 100000
    Addition---------14.88 secondes
    AdditionSJR------15.06 secondes
    Addition2EBVbis---3.37 secondes
    AdditionProc------4.00 secondes
    AdditionProc1-----6.78 secondes
    AdditionProc2-----6.78 secondes
     
    //et si j'enleve l'optimisation de delphi....
    Addition---------19.36 secondes
    AdditionSJR------19.83 secondes
    Addition2EBVbis---9.22 secondes
    AdditionProc------9.17 secondes
    AdditionProc1-----10.28 secondes
    AdditionProc2-----10.28 secondes
    Mais je me demande pourquoi la AdditionProc n'est pas plus rapide.?.?
    l'optimisation de delphi est vraiment surprenante!
    Comment dupliquer un disque...ça vous intéresse?
    Tutoriel et code source delphi ici

Discussions similaires

  1. Nombres de chiffres significatif avec fortran
    Par VauRDeC dans le forum Fortran
    Réponses: 7
    Dernier message: 09/06/2012, 03h42
  2. Problème avec if .. else if.. else dans une fonction
    Par marwa21 dans le forum MS SQL Server
    Réponses: 5
    Dernier message: 21/04/2011, 10h37
  3. chiffres significatifs avec plot
    Par Pierre13Th dans le forum MATLAB
    Réponses: 2
    Dernier message: 31/05/2009, 20h24
  4. Nombres de chiffre significatifs sur une figure
    Par lanfou dans le forum MATLAB
    Réponses: 4
    Dernier message: 04/06/2008, 11h36
  5. Réponses: 3
    Dernier message: 07/05/2008, 13h30

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