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

Delphi Discussion :

Algorithme de Boyer-Moore


Sujet :

Delphi

  1. #1
    Membre actif

    Homme Profil pro
    Inscrit en
    Mars 2009
    Messages
    128
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Vendée (Pays de la Loire)

    Informations forums :
    Inscription : Mars 2009
    Messages : 128
    Points : 203
    Points
    203
    Par défaut Algorithme de Boyer-Moore
    Bonjour,

    Mes amis, j'ai besoin d'un test de confirmation. J'ai voulu, comme beaucoup d'autres, implémenter MA version de l'algorithme de Boyer-Moore pour effectuer des recherches d'occurences dans des collections d'Octets. Je me suis placé dans deux problématiques :

    1 - Rester dans du générique; il s'agit de chercher une collection d'octets dans une autre collection d'octets plus grande, quels que soient les conteneurs (buffers, streams, strings, array of byte... etc) et quelles ques soient les types de collections (Texte, octets divers...)

    2 - Dépasser la limite des 256 octets pour l'occurence à chercher

    Bref, j'ai donc développé ma petite dll perso qui tourne magnifiquement bien chez moi (D7-Windows XP). Mais avant d'en publier les codes du source, j'aimerais savoir si véritablement elle tourne aussi bien ailleurs.

    PosBM.zip

    Pour l'utiliser il faut déposer cette dll dans le répertoire du programme appelant. Puis placer les routines appelables en implémentation :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    procedure InitSkipBuf(SStr : Pointer; LenSStr: longword); StdCall; external'PosBM';
    function PosBM_KR(SStr, Str : Pointer; LSStr, LStr, Depuis :longWord): longword; stdcall; external'PosBM';
    PosBM_KR s'utilise comme Pos() de Delphi. Mais auparavant, il convient d'appeler au moins une fois la procedure InitSkipBuf qui permet de remplir la fameuse table des sauts du Boyer-Moore.

    Voici comment je l'ai testée chez moi :
    (il faut une fenêtre avec un TButton et un TMemo)
    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
     
    unit Unit1;
     
    interface
     
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls;
     
    type
      TForm1 = class(TForm)
        Memo1: TMemo;
        Button1: TButton;
        procedure Button1Click(Sender: TObject);
      private
        { Déclarations privées }
      public
        { Déclarations publiques }
      end;
     
    var
      Form1: TForm1;
     
    implementation
     
    {$R *.dfm}
    // Dll PosBM *******************************************************************
     
    procedure InitSkipBuf(SStr : Pointer; LenSStr: longword); StdCall; external'PosBM';
    function PosBM_KR(SStr, Str : Pointer; LSStr, LStr, Depuis :longWord): longword; stdcall; external'PosBM';
     
    // GILBERT *********************************************************************
     
    const MNA: array[Char] of Char
      = #0#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 +
        ' !"#$%&''()*+,-./0123456789:;<=>?' +
        '@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_' +
        '`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~'#127 +
        '€'#129'‚ƒ„…†‡ˆ‰S‹Œ'#141'Z'#143#144'‘’“”•–—˜™S›Œ'#157'ZY' +
        #160'¡¢£¤¥¦§¨©ª«¬*®¯°±²³´µ¶·¸¹º»¼½¾¿' +
        'AAAAAAÆCEEEEIIIIDNOOOOO×OUUUUYÞß' +
        'AAAAAAÆCEEEEIIIIDNOOOOO÷OUUUUYÞY';
     
    function StrAleatoireMinus(Len: LongWord): AnsiString;
    var i: longWord; R: Integer;
    begin
      SetLength(Result, Len);
      for i := 1 to Len do begin
        R := random(123 - 97); R := R + 97; Result[i] := Chr(R);
      end;
    end;
     
    function StrAleatoireMajus(Len: LongWord): AnsiString;
    var i: longWord; R: Integer;
    begin
      SetLength(Result, Len);
      for i := 1 to Len do begin
        R := random(91 - 65); R := R + 65; Result[i] := Chr(R);
      end;
    end;
     
    // ***************************************************************************
     
    procedure TForm1.Button1Click(Sender: TObject);
        var Texte, Mot,Separ : string;
        NbTours,i,j,Occ,Depuis:longword;
        Gtc1,Gtc2 : Int64;
        procedure Trace(S : string);
        begin
             Memo1.Lines.Add(S);
        end;
    begin
      Randomize;
      Mot :=StrAleatoireMajus(400);
      Separ :=StrAleatoireMajus(1020);
      Texte := '';
      initskipBuf(@Mot[1],length(Mot));
      NbTours:=100000;
      for i := 1 to 10 do Texte :=  Mot +  Separ + Texte;
      Trace('Texte : '+Texte); Trace(' ');
      Trace('Mot : '+Mot); Trace(' ');
      Trace('Mot de '+IntToStr (length(Mot))+' Chr');
      Trace('Texte de '+IntToStr(length(Texte))+' Chr');
      Trace('pour '+IntToStr(NbTours)+' tours :'); trace(' ');
      Gtc1 := GetTickCount;
      for i:=1 to NbTours do begin
        Depuis:=1; j:=0; Occ:=0;
        repeat
            j:=PosBM_KR(@Mot[1],@Texte[1],length(Mot),length(Texte),Depuis);
            if j>0 then begin
             inc(Occ); Depuis:=j+Length(Mot);
            end;
        until j=0;
      end;
      Gtc2:=GetTickCount;
      Trace(IntToStr(Occ)+' occurences trouvées en '+IntToStr(Gtc2-Gtc1)+ ' ms');
      Trace(' ');
    end;
     
    end.
    Merci de me dire si ça tourne comme il faut...

  2. #2
    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,

    Merci de me dire si ça tourne comme il faut...
    Oui, ça tourne comme il faut, et voici un petit comparatif :

    A) Pour 100 000 Recherches de Mot de 175 caractères aléatoires dans Texte de 97 351 caractères aléatoires et Mot présent 16 fois dans chaque texte

    - Avec StrUtils.PosEx ASM version => Trouvé : 1 600 000 fois, Mis : 1 919 ms

    - Avec PosBM_KR => Trouvé : 1 600 000 fois, Mis : 577 ms

    B) Pour 1 000 000 Recherches de Mot de 510 caractères aléatoires dans Texte de 15 300 caractères aléatoires et Mot présent 10 fois dans chaque texte

    - Avec StrUtils.PosEx ASM version => Trouvé : 10 000 000 fois, Mis : 3 541 ms

    - Avec PosBM_KR => Trouvé : 10 000 000 fois, Mis : 4 197 ms

    C) Pour 10 000 Recherches de Mot de 4 caractères 'MOTF' dans Texte de ZOLA de 1 048 842 caractères et Mot présent 1 fois à la fin du texte

    - Avec StrUtils.PosEx ASM version => Trouvé : 10 000 fois, Mis : 1 997 ms

    - Avec PosBM_KR => Trouvé : 10 000 fois, Mis : 13 073 ms

    Le problème avec les tests comparatifs de vitesse avec le Boyer-Moore est que ses temps d'exécution dépendent des statistiques et varient en fonction du Mot recherché, de sa longueur et celle du Texte, ainsi que de l'absence/présence et fréquence de présence du Mot dans le Texte.
    L'idéal pour le Boyer-Moore est de chercher un Mot ou une Phrase très longue dans un nombre élevé de Textes dans lesquels le Mot ou la Phrase est absent(e) sauf par exemple dans un ou deux car dans ceux où il ou elle est absent(e) le Boyer-Moore avance à grands pas.
    Par contre pour la recherche de Mots très courts : plus il est court, et plus c'est la cata :

    D) Pour 10 000 Recherches de Mot de 3 caractères 'MOT' dans Texte de ZOLA de 1 048 842 caractères et Mot présent 1 fois à la fin du texte

    - Avec StrUtils.PosEx ASM version => Trouvé : 10 000 fois, Mis : 2 028 ms

    - Avec PosBM_KR => Trouvé : 10 000 fois, Mis : 17 425 ms

    En fait pour être gagnant à tous les coups, vu les résultats ci-dessus, il faudrait une routine qui dans "certaines conditions" appelle PosBM_KR et dans d'autres appelle PosEx ou une similaire à PosEx, de façon a bénéficier pleinement des performances de chacune .
    Reste à déterminer ces conditions, mais ça c'est encore un autre problème.

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

  3. #3
    Membre actif

    Homme Profil pro
    Inscrit en
    Mars 2009
    Messages
    128
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Vendée (Pays de la Loire)

    Informations forums :
    Inscription : Mars 2009
    Messages : 128
    Points : 203
    Points
    203
    Par défaut
    Bonjour et grand merci Gilbert

    Tu as très bien répondu à ma demande qui était : est-ce que ça tourne comme il faut chez vous ?

    L'intérêt de mon implémentation n'est pas de tenter de faire jeu égal avec PosEx version ASM (dans strsysutils depuis D 2005 ?) Cette dernière, si je ne dis pas de bêtise est un brute force avec une recherche basée sur du DWords à DWords avec en plus je crois l'adaptabilité aux nouvelles strings de Delphi. Bien. Mais uniquement des strings Delphi !

    J'ai bien précisé au départ que je me voulais généraliste : pouvoir rechercher une ou des collections d'octets (en pouvant dépasser la limite des 256 jusqu'à 2^32) parmi une collection d'octets plus grande, quels que soient les conteneurs et les contenus (et pas uniquement des chr dans des strings de Delphi).

    En plus l'implémentation en dll permet de ne pas se consacrer uniquement à Delphi, mais peut aussi intéresser d'autres LHN sous windows.

    C'est donc un exemple basé sur l'algorithme de Boyer-Moore avec ses avantages et aussi ses inconvénients. Si quelqu'un est vraiment intéressé, je suis prêt à présenter le source et faire le plus possible de commentaires.

  4. #4
    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,

    Rekin85 : L'intérêt de mon implémentation n'est pas de tenter de ..." :
    Quels sont donc les principes de ta démarche d'implémentation ???
    Puis il y a certainement des lecteurs qui aimeraient bien pouvoir jeter un coup d'œil sur le code qui a créé la dll compilée du *.ZIP
    Car je suppose que si t'as ouvert la présente discussion c'est pour obtenir éventuellement des suggestions et idées en vue de peaufiner le code.

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

  5. #5
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 447
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 447
    Points : 24 849
    Points
    24 849
    Par défaut
    J'ignore la particulartié de l'Algorithme de Boyer-Moore

    Si veux comparer ton algo avec une recherche générique dans un buffer, regarde ma fonction [post=5907510]SearchBinaryInBinary[post]
    Cela utilise CompareMem qui lui aussi triche avec les DWord mais sur un pointeur et non sur une chaine
    Pour la limite c'est 4Go à cause de l'utilisateur type Cardinal équivalent du longword
    Si l'on veut dépasser cette limite et conserver une compatibilité multi-langage,
    il faut utiliser le TLargeInteger (LARGE_INTEGER dans Winapi)

    Gilbert Geyer, peux-tu ajouter le comparatif SearchBinaryInBinary pour voir ce que cela donne,
    c'est un algo très simpliste mais purement Pointer



    EDIT : Lorsque j'ai lu le sujet hier et que j'ai vu que seul le binaire DLL était fourni, j'ai quitté le sujet même si je suis fan de ce genre de question
    Je ne vois pas l'intérêt de tester un code sans pouvoir le lire !
    La DLL est compilé en Ansi donc si c'est Delphi, c'est un vieux Dephi non Unicode encore moins 64bits, tu seras toujours limité au 2Go
    Est-ce même une DLL en Delphi, j'ai l'impression qu'il n'y aucun uses Delphi hormis l'unité Windows.
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  6. #6
    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
    Re-bonjour,


    ShaiLeTroll : J'ignore la particularité de l'Algorithme de Boyer-Moore
    Sa particularité consiste à associer au Mot recherché une Table de Sauts de 256 valeurs égales :
    - à Length(Mot) pour tous les Chr qui sont absents du Mot,
    - et pour chaque Chr du Mot la plus petite distance qui le sépare du Chr terminal (la plus petite car un Mot peut contenir plusieurs fois le même Chr)
    Si on cherche par exemple le Mot coulissant 'Delphi' positionné en début de recherche comme-ci après dans le Texte 'oolDelphiooo'
    la Table de Sauts vaut 3 pour le l de Delphi

    donc si dans cette position on a un l sous le i terminal le saut provoqué par la Table de Sauts positionne le Mot-coulissant comme suit avec ce saut de 3
    ... et dans cette position où il y a concordance entre le i terminal et celui du texte il ne reste plus qu'à vérifier si les autres Chr du Mot concordent avec ceux du Texte et :
    - si oui alors on a trouvé le mot,
    - sinon on continue à avancer avec la valeur du saut correspondant au Chr situé sous le i terminal du mot.

    L'intérêt majeur est que si on cherche une Phrase longue dans une flopée de textes où elle est absente on avance le plus souvent à grands pas de longueur égale à cette phrase, et ce n'est que si on tombe sur un Texte
    qui la contient qu'on est obligé de vérifier si tous les autres Chr situés devant le i terminal concordent avec ceux du texte

    Pour résumer la recherche d'une concordance sur le Chr terminal agit comme un détecteur qui dit si oui ou non le Mot peut être présent dans cette position et si ça vaut le coup de vérifier sa présence ou s'il vaut mieux cavaler en suivant la table des sauts.

    Gilbert Geyer, peux-tu ajouter le comparatif SearchBinaryInBinary pour voir ce que cela donne, c'est un algo très simpliste mais purement Pointer
    Voici :

    A) Pour 1 000 000 Recherches de Mot de 510 caractères aléatoires dans Texte de 15 300 caractères aléatoires et Mot présent 10 fois dans chaque texte

    - Avec StrUtils.PosEx ASM version => Trouvé : 10 000 000 fois, Mis : 3 447 ms

    - Avec PosBM_KR => Trouvé : 10 000 000 fois, Mis : 4 212 ms

    - Avec SearchBinaryInBinary => Trouvé : 10 000 000 fois, Mis : 159 792 ms

    B) Pour 10 000 Recherches de Mot de 4 caractères 'MOTF' dans Texte de ZOLA de 1 048 842 caractères et Mot présent à la fin du Texte

    - Avec StrUtils.PosEx ASM version => Trouvé : 10 000 fois, Mis : 1 997 ms

    - Avec PosBM_KR => Trouvé : 10 000 fois, Mis : 13 104 ms

    - Avec SearchBinaryInBinary => Trouvé : 10 000 fois, Mis : 163 333 ms

    C) Pour 100 000 Recherches de Mot de 175 caractères aléatoires dans Texte de 97 351 caractères aléatoires et Mot présent 16 fois dans chaque texte

    - Avec StrUtils.PosEx ASM version => Trouvé : 1 600 000 fois, Mis : 1 919 ms

    - Avec PosBM_KR => Trouvé : 1 600 000 fois, Mis : 609 ms

    - Avec SearchBinaryInBinary => Trouvé : 1 600 000 fois, Mis : 146 500 ms

    SearchBinaryInBinary rame dans la choucroute. (1 600 000 fois SetLength(OffSets, Length(OffSets) + 1) qui freinent)
    En plus on compare un algo façon Boyer-Moore à un algo d'un autre genre.

    Bout de code utilisé pour les tests avec SearchBinaryInBinary
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
      ...
      GTC := GetTickCount;
      SearchBinary := StringToByteArray(Mot);
      KeepOffSet := True; AcceptOverlap := false; Threshold := MaxInt; Count := 0;
      for i := 1 to NbTours do begin
        SetLength(OffSets, 0);
        Count := Count + SearchBinaryInBinary(@Texte[1], LT, SearchBinary, OffSets, KeepOffSet, Threshold, AcceptOverlap);
      end;
      Trace(Format('- Avec %s => Trouvé : %.0n  fois, Mis : %.0n  ms', ['SearchBinaryInBinary',
        Count / 1, (GetTickCount - GTC) / 1]));
    Cordalement, et à +.
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  7. #7
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 447
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 447
    Points : 24 849
    Points
    24 849
    Par défaut
    C'est mauvais ! Mauvais !

    C'est pire que je ne l'aurais cru !

    Passe KeepOffSet à False pour voir ce que cela donne, tu pourras aussi retirer SetLength(OffSets, 0);Pour voir combien ça coute !
    Vu la médiocrité des performances, c'est en Delphi 7, normalement avec FastMM l'allocation de tableau est beaucoup moins douloureuse !

    La fonction a été conçue à partir de SearchBinaryInFile pour aider un membre du forum,
    je n'ai encore jamais eu l'occasion de l'utiliser réellement

    Effectivement une variante Boyer-Moore de SearchBinaryInBinary serait a prévoir, maintenant que j'ai compris le principe

    Peux-tu fournir le code de mesure des deux autre aussi
    l'algo d'appel n'est pas du tout le même,
    SearchBinaryInBinary ne s'appele qu'une fois
    PosEx/PosBM_KR s'appelle plusieurs fois
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  8. #8
    Membre actif

    Homme Profil pro
    Inscrit en
    Mars 2009
    Messages
    128
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Vendée (Pays de la Loire)

    Informations forums :
    Inscription : Mars 2009
    Messages : 128
    Points : 203
    Points
    203
    Par défaut Code de la dll
    Bonjour les amis,

    Je vais essayer de faire plaisir à chacun. Amical salut particulier à ShaiLeTroll que tous les delphistes connaissent bien.
    Tout d'abord je signale une petite erreur de bornes dans mon algo et voici la version expurgée de ma dll (jusqu'à ce qu'elle soit à nouveau dénoncée)

    PosBM.zip

    Je développe mes dll en ASM, mais comme je ne dispose que du Delphi version 7 perso et de Xp ou Vista, cela reste du code 32 bits... Mais si on prend la version bien compilée en 32, elle devrait (?) tourner également sur des versions plus récentes... (à démontrer). Oui il n'y a aucun autre uses que windows car il n'y a besoin de rien d'autre pour rester le plus généraliste possible (autres LHN).

    Certes, le Boyer-Moore possède des inconvénients, notemment le fait qu'il ait besoin d'établir préalablement une table de sauts, mais généralement il apporte un gros gain par rapport aux brute force même en DWords. Les particularités de l'algorithme proposé ici sont d'une part l'élargissement de la recherche d'occurence plus grande que 256 octets et le fait qu'il s'adapte justement à cette taille : en deçà de 512 octets il travaille ses comparaisons en byte à byte, au-delà il travaille en dword à dword.

    Voici le code, les Delphistes peuvent l'inclure directement dans leurs implémentations s'ils ne veulent pas utiliser la dll, mais ATTENTION c'est du code 32 bits !

    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
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    library PosBM;
     
    uses
      windows;
     
    // Routines internes ***********************************************************
     
    type TSkip = array[0..255] of longword;
    var  SkipBuf: TSkip;
     
    // Compare SStr à Str depuis la position de edx dans Str
    // comparaisons faites en dwords
    // Entrée :
    // 1 - esi pointe sur la Str et edi sur la SStr
    // 2 - ecx contient l'indice de la borne
    // 3 - edx contient la longueur de la collection SStr
    // Retour :
    // 1 - CarryFlag à 1 si occurence trouvée et à 0 sinon
    // 2 - ecx renvoie la position du byte d'arrêt sur Str
    procedure CompBM_D; register;
    asm
       push    edi
       push    esi            // adresse départ Str
       add     esi,ecx        // placer esi sur la borne de départ
       mov     ecx,edx        // edx garde length(SStr)
       // comparaison descendante
       std
       add     esi,ecx        // pointer fin Str + 1
       add     edi,ecx        // pointer fin SStr + 1
       // Byte à Byte
       @Bytes:
       and     ecx,$3         // combien de bytes en reste ?
       jz      @DWords        // aucun
       @RBytes:
         dec     esi          // se placer sur dernier byte
         dec     edi
         mov     al,byte ptr[edi]
         cmp     al,byte ptr[esi]
         jne     @FinNon      // byte discordant
         dec     ecx
         jnz     @Rbytes
       // DWord à DWord
       @DWords:
       mov     ecx,edx        // combien de DWords entiers ?
       shr     ecx,$2
       jz      @FinOui        // aucun
       @RDWords:
         sub     esi,$4       // se placer dword en dessous
         sub     edi,$4
         mov     eax,DWord ptr[esi]
         cmp     eax,DWord ptr[edi]
         jne     @ByteD       // si pas égaux, aller au byte défaillant
         dec     ecx
         jnz     @RDWords
       jmp     @FinOui        // tous DWords bons
       @ByteD:                // cas d'un Dword défaillant
       mov     ecx,$4         // rattraper le décalage
       add     esi,ecx        // et chercher le byte défaillant
       @RByteD:
         dec     esi
         cmp     al,byte ptr[esi]
         jne     @FinNon
         shr     eax,$8
         dec     ecx
         jnz     @RByteD
       // Retours de routine
       @FinNon:              // retour false
       xor     eax,eax
       jmp     @Fin
       @FinOui:             // retour true
       mov     eax,$1
       @Fin:
       mov     ecx,esi
       pop     esi          // remise adresse Départ
       sub     ecx,esi      // calcul place du byte d'arrivée
       pop     edi
       shr     eax,$1       // positionnement du carry flag
    end;
     
    // Compare SStr à Str depuis la position de ecx dans Str
    // comparaisons faites en bytes à reculons
    // Entrée :
       // 1 - esi pointe sur la Str et edi sur la SStr
       // 2 - ecx contient l'indice de la borne de départ dans Str
       // 3 - edx contient la longueur de la collection SStr
    // Retour :
       // 1 - Carry Flag à 1 si occurence trouvée et à 0 sinon
       // 2 - ecx renvoie la position du byte d'arrêt sur Str
    procedure CompBM_B;
    asm
       push    edi
       push    esi            // adresse départ Str
       add     esi,ecx        // placer esi sur la borne de départ
       mov     ecx,edx        // ecx = length(SStr)
       // coulisseau
       mov     al,byte ptr[esi]
       cmp     al,byte ptr[edi]
       je      @coulisse
       add     esi,ecx
       dec     esi
       jmp     @FinNon
       @Coulisse:
       // comparaison descendante
       add     edi,ecx        // pointer fin SStr + 1
       add     esi,ecx        // pointer Str en rapport
       // Byte à Byte
       @RBytes:
         dec     esi
         dec     edi
         mov     al,byte ptr[edi]
         mov     ah,byte ptr[esi]
         cmp     ah,al
         jne     @FinNon      // byte discordant
         dec     ecx
         jnz     @Rbytes
       @FinOui:               // retour true
       mov     eax,$1
       jmp     @Fin
       @FinNon:               // retour false
       xor     eax,eax
       @Fin:
       mov     ecx,esi        // adresse byte arrêt
       pop     esi            // remise adresse Départ
       sub     ecx,esi        // calcul rang du byte d'arrivée
       pop     edi
       shr     eax,$1         // positionnement du carry flag
    end;
     
    // Routines exportables ********************************************************
     
    // Initialise le tableau Skip des sauts du Boyer-Moore
    // en fonction de la collection à rechercher
    procedure InitSkipBuf(SStr : Pointer; LenSStr: longword); StdCall;
    asm
      push    edi
      lea     edi,[SkipBuf]           // edi pointe SkipBuf
      push    esi
      mov     esi,[ebp]+$08           // esi pointe SStr
      mov     eax,[ebp]+$0C           // eax = len(SStr)
      // FillInt
      mov     ecx,$100                // 256 itérations
      rep     stosd                   // remplissage total avec lenSub
      sub     edi,$400                // remise edi au début de SkipBuf
      // boucle des sauts
      mov     ecx,eax                 // eax contient toujours len SStr
      @RSkip:
              dec    ecx
              jz     @Fin
              xor    eax,eax
              mov    al,byte ptr[esi]   // al contient le byte
              shl    eax,$2             // valeur du byte x 4
              mov    DWord ptr[edi+eax],ecx
              inc    esi
              jmp    @RSkip
      @Fin:
      pop     esi
      pop     edi
    end;
     
    // Algorithme de Boyer-Moore pour la recherche d'occurence
    // d'une collection de bytes dans une autre collection de bytes plus grande
    // L'occurence peut avoir une capacité de plus de 256 octets
    // Retourne le rang de la 1ère occurence trouvée à partir de Depuis
    // Retourne 0 si aucune trouvée
    // Routine orientée recherche par Bytes si LSStr<400 et DWords Si >400
    function PosBM_KR(SStr, Str : Pointer; LSStr, LStr, Depuis :longWord): longword; stdcall;
    var  PosMax,Depart : longWord;
    asm
      push     ebx
      lea      ebx,[SkipBuf]           // ebx pointe la Table de sauts
      push     edi
      mov      edi,[ebp]+$08           // edi pointe SStr
      push     esi
      mov      esi,[ebp]+$0C           // esi pointe Str
      mov      edx,[ebp]+$10           // edx garde la longueur de SStr
      mov      eax,[ebp]+$14
      sub      eax,edx
      jl       @FinNulle               // si SStr>Str
      mov      PosMax,eax              // AMax = Borne supérieure extrême
      mov      ecx,[ebp]+$18
      dec      ecx                     // ecx = variable Depuis
      cmp      edx,$1FF
      jg       @WhileD
      @WhileB:                         // Tant que pas trouvée ou fin Str
      mov      Depart,ecx
      cmp      PosMax,ecx
      jb       @FinNulle               // Fin de Str
      call     CompBM_B                // ecx = rang occurence si CF=1
      jc       @FinBonne               // CF indicateur oui - non
      xor      eax,eax                 // pas trouvée, on saute en BM
      mov      al,byte ptr[esi]+ecx    // byte d'arrêt
      shl      eax,$2                  // indice x 4 pour DWord
      mov      ecx,DWord ptr[ebx]+eax  // décalage par SkipBuf[byte d'arrêt]
      add      ecx,Depart
      jmp      @WhileB
      @WhileD:                          // Tant que pas trouvée ou fin Str
      mov      Depart,ecx
      cmp      PosMax,ecx
      jb       @FinNulle               // Fin de Str
      call     CompBM_D                // ecx = rang occurence si CF=1
      jc       @FinBonne               // CF indicateur oui - non
      xor      eax,eax                 // pas trouvée, on saute en BM
      mov      al,byte ptr[esi]+ecx    // byte d'arrêt
      shl      eax,$2                  // indice x 4 pour DWord
      mov      ecx,DWord ptr[ebx]+eax  // décalage par SkipBuf[byte d'arrêt]
      add      ecx,Depart
      jmp      @WhileD
      @FinNulle:
      xor      eax,eax
      jmp      @Fin
      @FinBonne:
      inc      ecx
      mov      eax,ecx                 // retour du rang de l'occurence trouvée
      @Fin:
      pop      esi
      pop      edi
      pop      ebx
    end;
     
    // *****************************************************************************
     
    exports
          InitSkipBuf,
          PosBM_KR;
     
    // *****************************************************************************
     
    begin
    end.
    Je reste ouvert à plus amples explications s'il le faut...

  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
    Re-salut,

    ShaiLeTroll : Passe KeepOffSet à False pour voir ce que cela donne, tu pourras aussi retirer SetLength(OffSets, 0);Pour voir combien ça coute !
    Voici les résultats :
    Pour 1 000 000 Recherches de Mot de 510 caractères aléatoires dans Texte de 15 300 caractères aléatoires et Mot présent 10 fois dans chaque texte

    - Avec StrUtils.PosEx ASM version => Trouvé : 10 000 000 fois, Mis : 3 681 ms

    - Avec PosBM_KR => Trouvé : 10 000 000 fois, Mis : 4 243 ms

    - Avec SearchBinaryInBinary => Trouvé : 10 000 000 fois, Mis : 159 059 ms < Pas de grand changement


    Peux-tu fournir le code de mesure des deux autre aussi
    l'algo d'appel n'est pas du tout le même,
    SearchBinaryInBinary ne s'appele qu'une fois
    PosEx/PosBM_KR s'appelle plusieurs fois
    Le voici :

    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
     
      ...
      LM := length(Mot); LT := length(Texte);
     
      Trace(' '); //<= Trace = RichEdit.Lines.Add(s) 
     
      GTC := GetTickCount; Count := 0;
     
      for i := 1 to nbTours do begin
        Depuis := 1;
        Po := PosEx(Mot, Texte, Depuis);
        while Po > 0 do begin
          inc(Count);
          Depuis := Po + LM + 1;
          if Depuis >= LT then break;
          Po := PosEx(Mot, Texte, Depuis);
        end;
      end;
      Trace(Format('- Avec %s => Trouvé : %.0n  fois, Mis : %.0n  ms', ['StrUtils.PosEx ASM version',
        Count / 1, (GetTickCount - GTC) / 1]));
     
      Trace(' ');
      InitSkipBuf(@Mot[1], length(Mot)); //<= Initialisation de la Table des sauts associée au "Mot" à chercher dans une collection de Textes
      Count := 0; GTC := GetTickCount;
     
      for i := 1 to NbTours do begin
        DepuisDW := 1; PoDW := 0;
        repeat
          PoDW := PosBM_KR(@Mot[1], @Texte[1], length(Mot), length(Texte), DepuisDW);
          if PoDW > 0 then begin
            inc(Count); 
            DepuisDW := PoDW + Length(Mot); //<= Pour la recherche de l'occurrence suivante
          end;
        until PoDW = 0;
      end;
      Trace(Format('- Avec %s => Trouvé : %.0n  fois, Mis : %.0n  ms', ['PosBM_KR',
        Count / 1, (GetTickCount - GTC) / 1]));
     
      Trace('');
      GTC := GetTickCount;
      SearchBinary := StringToByteArray(Mot);
      KeepOffSet := False;
      AcceptOverlap := false; Threshold := MaxInt; Count := 0;
      for i := 1 to NbTours do begin
        //SetLength(OffSets, 0);
        Count := Count + SearchBinaryInBinary(@Texte[1], LT, SearchBinary, OffSets, KeepOffSet, Threshold, AcceptOverlap);
      end;
      Trace(Format('- Avec %s => Trouvé : %.0n  fois, Mis : %.0n  ms', ['SearchBinaryInBinary',
        Count / 1, (GetTickCount - GTC) / 1]));
    Effectivement une variante Boyer-Moore de SearchBinaryInBinary serait a prévoir, maintenant que j'ai compris le principe
    Oui, ça vaudrait le coup...

    Cordialement, et à +.
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  10. #10
    Membre éprouvé
    Avatar de Cirec
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    467
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 467
    Points : 1 072
    Points
    1 072
    Par défaut
    Salut,

    Bref ... vous semblez ignorer le fait que l'on peut rechercher du binaire avec des fonctions classiques
    qui ne demandent que du texte (string) en entrée !!!

    il suffit de charger ces données correctement dans une string et la recherche fonctionne très bien

    ... et la prétendue limite des 256 caractères de la chaine de recherche du Boyer-Moore n'existe pas

  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
    Re-salut,

    Cirec :... et la prétendue limite des 256 caractères de la chaine de recherche du Boyer-Moore n'existe pas
    En fait "Dépasser la limite des 256 octets pour l'occurrence à chercher" ça date de l'époque des SkipTables du type array[char] of byte mais c'est fini on est passé au longWord depuis un moment.

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

  12. #12
    Membre actif

    Homme Profil pro
    Inscrit en
    Mars 2009
    Messages
    128
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Vendée (Pays de la Loire)

    Informations forums :
    Inscription : Mars 2009
    Messages : 128
    Points : 203
    Points
    203
    Par défaut
    Bonsoir,
    il suffit de charger ces données correctement dans une string et la recherche fonctionne très bien
    Soit ! mais si dans ces données il y a des bytes de valeur 0, comment demander à Delphi d'en donner la longueur exacte ?

    Maintenant, j'ai bien dit que ma demande consistait à savoir si mon code "tournait" bien sur d'autres machines que la mienne, ce qui n'est pas encore une certitude... Il faut rester modeste.

    Quant à la philosophie du Boyer-Moore ou d'autres méthodes, je ne me place absolument pas dans cette problématique là. Chacun fait comme il veut...

  13. #13
    Membre éprouvé
    Avatar de Cirec
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    467
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 467
    Points : 1 072
    Points
    1 072
    Par défaut
    re,
    Citation Envoyé par Gilbert Geyer
    En fait "Dépasser la limite des 256 octets pour l'occurrence à chercher" ça date de l'époque des SkipTables du type array[char] of byte mais c'est fini on est passé au longWord depuis un moment.
    oui je le sais mais c'est Rekin85 qui répète qu'il voudrait passer cette barrière.

    Citation Envoyé par Rekin85 Voir le message
    ... Soit ! mais si dans ces données il y a des bytes de valeur 0, comment demander à Delphi d'en donner la longueur exacte ?
    Ben si tu avais lu et testé le code tu aurais vite vu que ça ne pose aucun problème ...
    l'image que l'on recherche a quelques bytes de valeur 0
    et l'exécutable dans lequel on cherche en a beaucoup plus et dès le début du fichier.
    Donc, si ça ne fonctionnait pas on ne trouverait rien ou on aurait une erreur ... !!!

    Cordialement,
    @+ Cirec

  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
    Bonjour,

    ShaiLeTroll : Effectivement une variante Boyer-Moore de SearchBinaryInBinary serait a prévoir, maintenant que j'ai compris le principe
    Juste fait par curiosité pour voir ce que donne un Boyer-Moore avec CompareMem :
    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
    type TByteDynArray = array of Byte;
     
    function StringToByteArray(const S: AnsiString): TByteDynArray;
    var
      Len: Integer;
    begin
      Len := Length(S);
      SetLength(Result, Len);
      Move(S[1], Result[0], Len);
    end;
     
    type tSkip2 = array[char] of longWord;
    var Skip2: tSkip2;
     
    procedure InitSkip2(const Mot: string);
    var LM, k: integer; Cara: char;
    begin
      LM := Length(Mot);
      for Cara := low(Char) to high(Char) do Skip22[Cara] := LM;
      for k := 1 to LM - 1 do Skip22[Mot[k]] := LM - k;
    end;
     
    function BMHSearchBinaryInBinary(const Buffer: Pointer; BufferLen: Cardinal; var StartPos: Cardinal; const SearchBinary: TByteDynArray): Integer;
    // @param Buffer Pointeur sur une Zone Mémoire de 4Go maximum
    // @param BufferLen Longueur de la Zone Mémoire
    // var StartPos = Position de départ de la recherche en entrée, renvoie en sortie le Position de départ pour la recherche de l'occurrence suivante
    // @param SearchBinary Tableau de Byte à chercher dans la Zone Mémoire
    // @Result : renvoie la position de la Première occurrence trouvée depuis StartPos
    var
      ik, dk, LM, LM1: Cardinal;
      BufferCurPos: PByte;
      WantedCurPos: PByte;
    begin
      Result := 0;
      LM := Length(SearchBinary); if LM <= 0 then EXIT;
     
      BufferCurPos := Buffer;
      WantedCurPos := @SearchBinary[0];
      LM1 := LM - 1;
      ik := StartPos + LM1;
     
      Inc(BufferCurPos, ik);
      WantedCurPos := @SearchBinary[LM1];
     
      while (ik <= BufferLen) do begin
        if CompareMem(BufferCurPos, WantedCurPos, 1) then begin // if (Texte[ik] = Mot[LM]) then begin
          Dec(BufferCurPos, LM1);
          WantedCurPos := @SearchBinary[0];
          if CompareMem(BufferCurPos, WantedCurPos, LM1) then begin
            Result := ik - LM1 + 1;
            StartPos := ik + 1;
          end;
        end;
        dk := skip22[Chr(BufferCurPos^)];
        Inc(ik, dk); //< lourdeur
        Inc(BufferCurPos, dk);
      end;
    end;
    Et pour les tests :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    Trace('');
      GTC := GetTickCount; InitSkip2(Mot); SearchBinary := StringToByteArray(Mot);
      Count := 0; LT:=Length(Texte);
      for i := 1 to nbTours do begin
        StartPos := 0;
        Po := BMHSearchBinaryInBinary(@Texte[1], LT, StartPos, SearchBinary);
        while Po > 0 do begin
          inc(Count);
          if StartPos >= LT then break;
          Po := BMHSearchBinaryInBinary(@Texte[1], LT, StartPos, SearchBinary);
        end;
      end;
      Trace(Format('- Avec %s => Trouvé : %.0n  fois, Mis : %.0n  ms', ['BMHSearchBinaryInBinary',
        Count / 1, (GetTickCount - GTC) / 1]));
    Résultats :

    A) Pour 100 000 Recherches de Mot de 175 caractères aléatoires dans Texte de 97 351 caractères aléatoires et Mot présent 16 fois dans chaque texte

    - Avec StrUtils.PosEx ASM version => Trouvé : 1 600 000 fois, Mis : 1 903 ms

    - Avec PosBM_KR => Trouvé : 1 600 000 fois, Mis : 639 ms

    - Avec BMHSearchBinaryInBinary => Trouvé : 1 600 000 fois, Mis : 19 407 ms à comparer avec les résultats d'hier pour SearchBinaryInBinary => Trouvé : 1 600 000 fois, Mis : 146 500 ms
    soit une vitesse multipliée par 7,55 grâce à Boyer-Moore


    B) Pour 1 000 000 Recherches de Mot de 510 caractères aléatoires dans Texte de 15 300 caractères aléatoires et Mot présent 10 fois dans chaque texte :

    - Avec StrUtils.PosEx ASM version => Trouvé : 10 000 000 fois, Mis : 3 308 ms

    - Avec PosBM_KR => Trouvé : 10 000 000 fois, Mis : 4 227 ms

    - Avec BMHSearchBinaryInBinary => Trouvé : 10 000 000 fois, Mis : 35 397 ms à comparer avec les résultats d'hier pour SearchBinaryInBinary => Trouvé : 10 000 000 fois, Mis : 159 792 ms
    soit une vitesse multipliée par 4,51 grâce à Boyer-Moore

    Par contre, dans les deux cas BMHSearchBinaryInBinary reste loin derrière PosEx et PosBM_KR
    Mais bon, on aura essayé ...

    Cirec : à propos de la limite des 256 : oui je le sais mais c'est Rekin85 qui répète qu'il voudrait passer cette barrière.
    Bin, c'était une phrase un peu maladroitement tournée. En fait les anciens Sauts de type byte ne constituaient de barrière qu'à la valeur maxi des Sauts de la SkipTable associée à une SubString de longueur supérieure à 256,
    alors qu'avec des Sauts de type LongWord le Boyer-Moore peu cavaler à sa guise.

    Cordialement, et à +.
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  15. #15
    Membre éprouvé
    Avatar de Cirec
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    467
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 467
    Points : 1 072
    Points
    1 072
    Par défaut
    re,
    Citation Envoyé par Gilbert Geyer
    Par contre, dans les deux cas BMHSearchBinaryInBinary reste loin derrière PosEx et PosBM_KR
    Mais bon, on aura essayé ...
    si tu veux encore gagner du temps il faut retirer les appels à CompareMem qui plombent les performances. Malgré que la comparaison soit faite en ASM ça n'en reste pas moins un appel à une procédure externe et ça c'est très couteux en temps.

    La ligne 46 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if CompareMem(BufferCurPos, WantedCurPos, 1) then begin
    pourrait se remplacer par :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if BufferCurPos^ = WantedCurPos^ then begin
    et adapter le reste du code avec le même principe ... ça devrait encore le booster un peu.
    Mais je ne pense pas que ce soit plus rapide qu'un Boyer-Moore en Pascal

    à voir
    Cordialement,
    @+ Cirec

  16. #16
    Membre actif

    Homme Profil pro
    Inscrit en
    Mars 2009
    Messages
    128
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Vendée (Pays de la Loire)

    Informations forums :
    Inscription : Mars 2009
    Messages : 128
    Points : 203
    Points
    203
    Par défaut
    Bonjour à tous,

    Cirec a dit :
    Ben si tu avais lu et testé le code tu aurais vite vu que ça ne pose aucun problème ...
    l'image que l'on recherche a quelques bytes de valeur 0
    et l'exécutable dans lequel on cherche en a beaucoup plus et dès le début du fichier.
    Donc, si ça ne fonctionnait pas on ne trouverait rien ou on aurait une erreur ... !!!
    Vu et pris note, j'ai lu et testé. C'est très bien, ça marche et rapide, très ingénieux. Cela corrobore bien ce que je pensais des recherches d'occurences d'une string dans une string par une fonction faite pour cela.

    Petite question : Les octets en question passent par des MemoryStreams, pourquoi avoir besoin de les recopier dans des strings de longueurs allouées (writebuffer...), alors qu'on les a déjà sous la main ? Bien pointés et bien comptés ?

  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
    Bonjour,


    Cirec : ... Remplacer la ligne 46 par if BufferCurPos^ = WantedCurPos^ then begin pour gagner du temps
    Cette simple modif conduit aux résultats suivants :

    A) Pour 100 000 Recherches de Mot de 175 caractères aléatoires dans Texte de 97 351 caractères aléatoires et Mot présent 16 fois dans chaque texte

    - Avec StrUtils.PosEx ASM version => Trouvé : 1 600 000 fois, Mis : 1 934 ms

    - Avec PosBM_KR => Trouvé : 1 600 000 fois, Mis : 577 ms

    - Avec BMHSearchBinaryInBinary => Trouvé : 1 600 000 fois, Mis : 2 761 ms

    Sacré gain de speed par rapport à hier et avant-hier:
    - Avec BMHSearchBinaryInBinary => Trouvé : 1 600 000 fois, Mis : 19 407 ms à comparer avec les résultats d'avant-hier pour SearchBinaryInBinary => Trouvé : 1 600 000 fois, Mis : 146 500 ms
    soit une vitesse multipliée par 146 500/2 761 = 53 grâce à Boyer-Moore et par 19 407/2 761 = 7 grâce à la suggestion de Cirec

    B) Pour 1 000 000 Recherches de Mot de 510 caractères aléatoires dans Texte de 15 300 caractères aléatoires et Mot présent 10 fois dans chaque texte

    - Avec StrUtils.PosEx ASM version => Trouvé : 10 000 000 fois, Mis : 3 370 ms

    - Avec PosBM_KR => Trouvé : 10 000 000 fois, Mis : 4 212 ms

    - Avec BMHSearchBinaryInBinary => Trouvé : 10 000 000 fois, Mis : 5 866 ms

    Sacré gain de speed par rapport à hier et avant-hier:
    - Avec BMHSearchBinaryInBinary => Trouvé : 10 000 000 fois, Mis : 35 397 ms à comparer avec les résultats d'avant-hier pour SearchBinaryInBinary => Trouvé : 10 000 000 fois, Mis : 159 792 ms
    soit une vitesse multipliée par 159 792/5 866 = 27 grâce à Boyer-Moore et par 35 397/5 866 = 6 grâce à la suggestion de Cirec

    Et dans les deux cas les performances de BMHSearchBinaryInBinary se rapprochent de plus en plus de celles de PosEx et de PosBM_KR.

    et adapter le reste du code avec le même principe ... ça devrait encore le booster un peu
    Bin vu les gains ça vaut bigrement le coup de remplacer également le if CompareMem(BufferCurPos, WantedCurPos, LM1) de la ligne 49

    En plus de ceci j'aimerais également pouvoir remplacer la lourdeur de la ligne 55 : Inc(ik, dk) qui ne sert qu'au while (ik <= BufferLen) de la ligne 45 je n'ai pas trouvé mieux pour éviter le dépassement de BufferLen.
    en ligne 45 un truc du genre while (BufferCurPos <= BufferLen) do begin qui permettrait de virer le Inc de la ligne 55 (mais while (BufferCurPos <= BufferLen) est Refusé par le compilo)

    Mais je ne pense pas que ce soit plus rapide qu'un Boyer-Moore en Pascal
    Je préfère quand même d'essayer car on n'arrête pas d'avoir des surprises...

    Cordialement, et à +.
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  18. #18
    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
    Re-salut,

    Cela valait effectivement le coup d'essayer : voici la version 2 de BMHSearchBinaryInBinary :
    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
    function BMHSearchBinaryInBinary2(const Buffer: Pointer; BufferLen: Cardinal; var StartPos: Cardinal; const SearchBinary: TByteDynArray): Integer;
    // @param Buffer Pointeur sur une Zone Mémoire de 4Go maximum
    // @param BufferLen Longueur de la Zone Mémoire
    // var StartPos = Position de départ de la recherche en entrée, renvoie en sortie le Position de départ pour la recherche de l'occurrence suivante
    // @param SearchBinary Tableau de Byte à chercher dans la Zone Mémoire
    // @Result : renvoie la position de la Première occurrence trouvée depuis StartPos
    var
      ik, dk, LM, LM1, R: Cardinal;
      BufferCurPos: PByte; // Position dans Buffer "Texte"
      WantedCurPos: PByte; // Position dans Buffer "Mot"
      BCurPos: PByte; // Idem pour marche à reculons
      WCurPos: PByte; // Idem pour marche à reculons
    
    begin
      Result := 0;
      LM := Length(SearchBinary); if LM <= 0 then EXIT;
    
      BufferCurPos := Buffer;
      WantedCurPos := @SearchBinary[0];
      LM1 := LM - 1;
      ik := StartPos + LM1;
    
      Inc(BufferCurPos, ik);
      WantedCurPos := @SearchBinary[LM1];
    
      while (ik <= BufferLen) do begin
        if BufferCurPos^ = WantedCurPos^ then begin
          BCurPos := BufferCurPos;
          WCurPos := WantedCurPos; R := LM1;
          repeat
            dec(BCurPos); dec(WCurPos); dec(R);
          until (R = 0) or (BufferCurPos^ <> WantedCurPos^);
          if (R = 0) then begin
            Result := ik - LM1 + 1;
            StartPos := ik + 1; EXIT;
          end;
        end;
        dk := skip22[Chr(BufferCurPos^)];
        Inc(ik, dk);
        Inc(BufferCurPos, dk);
      end;
    end;
    Et voici un Boyer-Moore basique en Pascal :
    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 BMHPascalNaif(const Mot, Texte: AnsiString; var Depuis: longWord): boolean;
    var rm, im, it, ik, LM, LT: integer;
    begin
      Result := false; LM := Length(Mot); LT := length(Texte);
      if (LM = 0) or (LT = 0) then EXIT;
      ik := Depuis + LM - 1;
      while (ik <= LT) do begin
        it := ik;
        im := LM; rm := LM - 1;
        if (Texte[it] = Mot[im]) and (Texte[it - rm] = Mot[1]) then begin
          repeat
            Dec(im);
            Dec(it);
          until (im = 0) or (Texte[it] <> Mot[im]);
          if im = 0 then begin
            Result := true; Depuis := it; EXIT; // Occurrence Trouvée
          end;
        end;
        Inc(ik, skip22[Texte[ik]]);
      end;
      Result := false; Depuis := 0;
    end;
    Et voici les résultats comparatifs :

    A) Pour 100 000 Recherches de Mot de 175 caractères aléatoires dans Texte de 97 351 caractères aléatoires et Mot présent 16 fois dans chaque texte :

    - Avec StrUtils.PosEx ASM version => Trouvé : 1 600 000 fois, Mis : 1 903 ms

    - Avec BMHPascalNaif (Case Sensitive) => Trouvé : 1 600 000 fois, Mis : 452 ms

    - Avec PosBM_KR ASM => Trouvé : 1 600 000 fois, Mis : 577 ms

    - Avec BMHSearchBinaryInBinary => Trouvé : 1 600 000 fois, Mis : 453 ms

    d'où facteur de gain de speed de BMHSearchBinaryInBinary par rapport à l'ancienne SearchBinaryInBinary = 146 500/453 = 323

    B) Pour 1 000 000 Recherches de Mot de 510 caractères aléatoires dans Texte de 15 300 caractères aléatoires et Mot présent 10 fois dans chaque texte :

    - Avec StrUtils.PosEx ASM version => Trouvé : 10 000 000 fois, Mis : 3 354 ms

    - Avec BMHPascalNaif (Case Sensitive) => Trouvé : 10 000 000 fois, Mis : 2 886 ms

    - Avec PosBM_KR ASM => Trouvé : 10 000 000 fois, Mis : 4 212 ms

    - Avec BMHSearchBinaryInBinary => Trouvé : 10 000 000 fois, Mis : 2 839 ms

    d'où facteur de gain de speed de BMHSearchBinaryInBinary par rapport à l'ancienne SearchBinaryInBinary 159 792/2 839 = 56

    On constate même que BMHPascalNaif et BMHSearchBinaryInBinary pédalent plus vite que les deux versions en ASM.

    Cordialement, et à +.
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  19. #19
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 447
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 447
    Points : 24 849
    Points
    24 849
    Par défaut
    Citation Envoyé par Gilbert Geyer Voir le message
    - Avec SearchBinaryInBinary => Trouvé : 10 000 000 fois, Mis : 159 059 ms < Pas de grand changement
    Donc ce n'était pas le SetLength qui coutait !
    C'est l'algo qui est lent !

    Comment PosEx fait-il pour être si rapide avec pourtant une approche simpliste de parcours de chaine
    Est-ce que le code Delphi fourni en "exemple" PUREPASCAL est le proche du code version ASM ?

    Je suis très intéressé par vos réponses, je vais lire tout cela !
    Au final, que la mise en place de Boyer-Moore produise un code plus rapide est très satisfaisant !

    Je vais m'en inspirer pour modifier SearchBinaryInFile qui est la vrai fonction que j'utilise
    J'ai un programme de recherche de fichier DMP (MiniDump) qui pourrait gagner en performance en appliquant Boyer-Moore sur la recherche de binaire dans un fichier
    On a des programmes vieux de 15 ans et certains, même si ils ont évolués plantent encore et génère des mini-dump qui saturent notre serveur (400Ko à 900Ko par minute pendant 3 jours, je vous laisse imaginer)


    Oui SearchBinaryInBinary n'est qu'un truc expérimental
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  20. #20
    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,

    En continuant les tests j'ai mis le doigt sur une petite erreur dans la version 2 de BMHSearchBinaryInBinary qui devient BMHSearchBinaryInBinary3 que voici :

    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
    function BMHSearchBinaryInBinary3(const Buffer: Pointer; BufferLen: Cardinal; var StartPos: Cardinal; const SearchBinary: TByteDynArray): Integer;
    // @param Buffer Pointeur sur une Zone Mémoire de 4Go maximum
    // @param BufferLen Longueur de la Zone Mémoire
    // var StartPos = Position de départ de la recherche en entrée, renvoie en sortie le Position de départ pour la recherche de l'occurrence suivante
    // @param SearchBinary Tableau de Byte à chercher dans la Zone Mémoire
    // @Result : renvoie la position de la Première occurrence trouvée depuis StartPos
    var
      ik, dk, LM, LM1, R: Cardinal;
      BufferCurPos: PByte; // Position dans Buffer "Texte"
      WantedCurPos: PByte; // Position dans Buffer "Mot"
      BCurPos: PByte; // Idem pour marche à reculons
      WCurPos: PByte; // Idem pour marche à reculons
    
    begin
      Result := 0;
      LM := Length(SearchBinary); if LM <= 0 then EXIT;
    
      BufferCurPos := Buffer;
      WantedCurPos := @SearchBinary[0];
      LM1 := LM - 1;
      ik := StartPos + LM1;
    
      Inc(BufferCurPos, ik);
      WantedCurPos := @SearchBinary[LM1];
      while (ik <= BufferLen) do begin
        if BufferCurPos^ = WantedCurPos^ then begin
          BCurPos := BufferCurPos;
          WCurPos := WantedCurPos; R := LM1;
          repeat
            dec(BCurPos); dec(WCurPos); dec(R);
          until (R = 0) or (BCurPos^ <> WCurPos^); // Ligne modifiée
          if (R = 0) then begin
            Result := ik - LM1 + 1;
            StartPos := ik + 1; EXIT;
          end;
        end;
        dk := skip22[Chr(BufferCurPos^)];
        Inc(ik, dk);
        Inc(BufferCurPos, dk);
      end;
    end;
    ShaiLeTroll : Donc ce n'était pas le SetLength qui coutait ! C'est l'algo qui est lent !
    Non ce n'était pas le SetLength qui coutait, c'est l'algo Non-Boyer-Moore et ses appels à CompareMem

    Comment PosEx fait-il pour être si rapide avec pourtant une approche simpliste de parcours de chaine
    Vu les commentaires laissés dans son code (All 4 Bytes, Check Next 4 Bytes of S, etc) il avance DWord à DWord.

    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
    function PosEx(const SubStr, S: string; Offset: Integer = 1): Integer;
    asm 
      push    ebx
      cmp     eax, 1
      sbb     ebx, ebx         {-1 if SubStr = '' else 0}
      sub     edx, 1           {-1 if S = ''}
      sbb     ebx, 0           {Negative if S = '' or SubStr = '' else 0}
      dec     ecx              {Offset - 1}
      or      ebx, ecx         {Negative if S = '' or SubStr = '' or Offset < 1}
      jl      @@InvalidInput
      push    edi
      push    esi
      push    ebp
      push    edx
      mov     edi, [eax-4]     {Length(SubStr)}
      mov     esi, [edx-3]     {Length(S)}
      add     ecx, edi
      cmp     ecx, esi
      jg      @@NotFound       {Offset to High for a Match}
      test    edi, edi
      jz      @@NotFound       {Length(SubStr = 0)}
      lea     ebp, [eax+edi]   {Last Character Position in SubStr + 1}
      add     esi, edx         {Last Character Position in S}
      movzx   eax, [ebp-1]     {Last Character of SubStr}
      add     edx, ecx         {Search Start Position in S for Last Character}
      mov     ah, al
      neg     edi              {-Length(SubStr)}
      mov     ecx, eax
      shl     eax, 16
      or      ecx, eax         {All 4 Bytes = Last Character of SubStr}
    @@MainLoop:
      add     edx, 4
      cmp     edx, esi
      ja      @@Remainder      {1 to 4 Positions Remaining}
      mov     eax, [edx-4]     {Check Next 4 Bytes of S}
      xor     eax, ecx         {Zero Byte at each Matching Position}
      lea     ebx, [eax-$01010101]
      not     eax
      and     eax, ebx
      and     eax, $80808080   {Set Byte to $80 at each Match Position else $00}
      jz      @@MainLoop       {Loop Until any Match on Last Character Found}
      bsf     eax, eax         {Find First Match Bit}
      shr     eax, 3           {Byte Offset of First Match (0..3)}
      lea     edx, [eax+edx-4] {Address of First Match on Last Character}
    @@Compare:
      inc     edx
      cmp     edi, -4
      jle     @@Large          {Lenght(SubStr) >= 4}
      cmp     edi, -1
      je      @@SetResult      {Exit with Match if Lenght(SubStr) = 1}
      mov     ax, [ebp+edi]    {Last Char Matches - Compare First 2 Chars}
      cmp     ax, [edx+edi]
      jne     @@MainLoop       {No Match on First 2 Characters}
    @@SetResult:               {Full Match}
      lea     eax, [edx+edi]   {Calculate and Return Result}
      pop     edx
      pop     ebp
      pop     esi
      pop     edi
      pop     ebx
      sub     eax, edx         {Subtract Start Position}
      ret
    @@NotFound:
      pop     edx              {Dump Start Position}
      pop     ebp
      pop     esi
      pop     edi
    @@InvalidInput:
      pop     ebx
      xor     eax, eax         {No Match Found - Return 0}
      ret
    @@Remainder:               {Check Last 1 to 4 Characters}
      sub     edx, 4
    @@RemainderLoop:
      cmp     cl, [edx]
      je      @@Compare
      cmp     edx, esi
      jae     @@NotFound
      inc     edx
      jmp     @@RemainderLoop
    @@Large:
      mov     eax, [ebp-4]     {Compare Last 4 Characters}
      cmp     eax, [edx-4]
      jne     @@MainLoop       {No Match on Last 4 Characters}
      mov     ebx, edi
    @@CompareLoop:             {Compare Remaining Characters}
      add     ebx, 4           {Compare 4 Characters per Loop}
      jge     @@SetResult      {All Characters Matched}
      mov     eax, [ebp+ebx-4]
      cmp     eax, [edx+ebx-4]
      je      @@CompareLoop    {Match on Next 4 Characters}
      jmp     @@MainLoop       {No Match}
    end; {PosEx}
    Est-ce que le code Delphi fourni en "exemple" PUREPASCAL est le proche du code version ASM ?
    Tout ce que je peux dire c'est que le code de BMHPascalNaif est tellement simple qu'on ne peut le simplifier davantage.
    Et pour ce qui concerne la version ASM de PosBM_KR je sais que "la dll est conçue pour changer d'algorithme au delà de 255 chr : en deçà, elle fait du byte à byte et au-delà du Dword à DWord"
    Mais seul Rekin85 pourra t'en dire plus.

    Pour ma part je regrette que sa dll ne soit pas conçue pour changer d'algorithme au delà de 4 chr : en deçà, elle ferait du byte à byte et au-delà du Dword à DWord.
    Pour pousser le bouchon encore un peu plus loin je verrais même une posBM_KR_DW en ASM simplifiée et qui effectuerait la recherche sur les 4 * K premiers Chr du Mot et qui fonctionnerait donc à 99 % en Dword à DWord.
    A mon avis une telle routine qui ignorerait les R derniers Chr du Mot (R = 0, 1, 2 ou 3 soit des broutilles) :
    - ne poserait aucun problème dans le recherche d'une séquence d'ADN puisque leur nombre de Chr est pile multiple de 4,
    - ne poserait pas non plus de problème pour la recherche d'un plagiat dont on ignore les 0 à 3 derniers Chr car le plus petit plagiat c'est au minimum une phrase, voire un ou plusieurs paragraphes de texte.
    - et dans les autres cas ne pas oublier le comportement d'un utilisateur qui va toujours au plus court :
    en tant qu'utilisateur de Google si je m'intéresse à "anticonstitutionellement" j'ai la flemme de taper ses 25 Chr et je m'arrête à environ la moitié donc si posBM_KR_DW ignore un ou deux Chr de plus ce n'est pas bien gênant,
    sans oublier que si un utilisateur veut à tout prix trouver exactement au Chr près son Mot complet il n'a qu'à utiliser une autre routine ou prendre l'habitude de ne chercher que des mots à nombre de Chr multiple de 4.

    Au final, que la mise en place de Boyer-Moore produise un code plus rapide est très satisfaisant !
    Effectivement, mais attention pour l'instant il n'est plus rapide que dans le cas de recherches de Mots ou de Phrases longues, pour des Mots courts PosEx est plus rapide
    en attendant une éventuelle posBM_KR_DW en ASM qui pourrait peut-être détrôner PosEx ...

    Mais en attendant on peut se tricoter un petit code qui appelle PosEx lorsque le Mot à chercher est court et qui appelle une Boyer-Moore lorsque le Mot ou la Phrase à chercher est longue ... histoire de bénéficier des performances des deux
    en toutes circonstances.

    Je vais m'en inspirer pour modifier SearchBinaryInFile qui est la vrai fonction que j'utilise
    J'ai un programme de recherche de fichier DMP (MiniDump) qui pourrait gagner en performance en appliquant Boyer-Moore sur la recherche de binaire dans un fichier
    On a des programmes vieux de 15 ans et certains, même si ils ont évolués plantent encore et génère des mini-dump qui saturent notre serveur (400Ko à 900Ko par minute pendant 3 jours, je vous laisse imaginer)
    Oui SearchBinaryInBinary n'est qu'un truc expérimental
    Bin quand on constate les gains de performances obtenus avec BMHSearchBinaryInBinary par rapport à SearchBinaryInBinary ce serait dommage de ne pas en profiter.
    On lui a taillé un short et enfilé des baskets de sprinteur.

    Cordialement, et à +.
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Implémentation algo boyer moore
    Par tony1.0 dans le forum C
    Réponses: 0
    Dernier message: 20/05/2010, 14h29
  2. Réponses: 2
    Dernier message: 29/12/2009, 11h57
  3. Boyer-moore VS strstr()
    Par riadh8 dans le forum Bibliothèque standard
    Réponses: 0
    Dernier message: 21/04/2009, 01h24
  4. algo Boyer Moore
    Par t-student dans le forum Algorithmes et structures de données
    Réponses: 8
    Dernier message: 20/04/2008, 10h19
  5. Code Source Boyer-moore
    Par kam42 dans le forum C++
    Réponses: 2
    Dernier message: 26/12/2007, 08h49

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