Fonction HexaToDecimal()

Pour discuter de l'assembleur
Anonyme2
Messages : 3518
Inscription : jeu. 22/janv./2004 14:31
Localisation : Sourans

Fonction HexaToDecimal()

Message par Anonyme2 »

Comme il n'y a pas beaucoup de code dans cette section, je vous propose (pour ceux qui veulent) de poster votre code asm pour créer une fonction qui va convertir une valeur hexadécimal (donc une chaine commençant par $) en une valeur décimal sur 32 bits.

- Le code devra ne devra être que de l'asm (pas de for i= ou des trucs dans le genre)

- Le format majuscule/minuscule de l'hexa devra être pris en compte

1 version avec la vérification du format hexa (c'est-à-dire on contrôle la présence du $ et que chaque caractère est bien un caractère hexa ainsi que la longueur de la chaine qui sera au max de 9 éléments)

1 variante sans vérification du format (sera donc plus rapide)

Si il y a une erreur, on retourne 0 (ou autre chose si vous avez une meilleur idée)

La rapidité à l'exécution est la chose primordiale.

une petite explication au début du code pour donner la méthode utilisée.

Ca vous dit ?

On pourra faire une librairie ensuite et y ajouter des fonctions
Le Soldat Inconnu
Messages : 4312
Inscription : mer. 28/janv./2004 20:58
Localisation : Clermont ferrand OU Olsztyn
Contact :

Message par Le Soldat Inconnu »

oui ;) et on pourrait faire de même pour la conversion bianaire vers décimal (d'ailleurs, on devrait commencer par ça car plus simple)
Je ne suis pas à moitié Polonais mais ma moitié est polonaise ... Vous avez suivi ?

[Intel quad core Q9400 2.66mhz, ATI 4870, 4Go Ram, XP (x86) / 7 (x64)]
erix14
Messages : 480
Inscription : sam. 27/mars/2004 16:44
Contact :

Message par erix14 »

Bonne idèe Denis :D

Code : Tout sélectionner

Procedure ValHex(Chaine.s)
          Valeur.l
          MOV ecx,Chaine
          CMP byte [ecx],'$'
          JNZ NonChaineHexa
          !LEA ebx,[TableValeur]
          MOV edx,0
          XOR eax,eax
          !Encore:
                    INC ecx
                    MOV al,byte [ecx]
                    CMP al,0
                    JE FinChaineHexa
                    XLATB
                    CMP al,$FF
                    JE NonChaineHexa
                    ROL edx,4
                    ADD edx,eax
                    JMP Encore
          !FinChaineHexa:
                    MOV Valeur,edx
                    ProcedureReturn Valeur
          !NonChaineHexa:
          ProcedureReturn 0
          !TableValeur:
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$0A,$0B,$0C,$0D,$0E,$0F,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$0A,$0B,$0C,$0D,$0E,$0F,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
EndProcedure
Debug ValHex("$10")
Debug ValHex("$1A0f")
Debug ValHex("10")
Debug ValHex("$1u0")
Excuse pour les explications... c'est 23 h 20 il faut que je dorme :D
Anonyme2
Messages : 3518
Inscription : jeu. 22/janv./2004 14:31
Localisation : Sourans

Message par Anonyme2 »

Le Soldat Inconnu a écrit :oui ;) et on pourrait faire de même pour la conversion bianaire vers décimal (d'ailleurs, on devrait commencer par ça car plus simple)
Oui, on pourra ajouter cette fonction, c'est proche de la fonction hexa --> déci dans le principe de base.
Anonyme2
Messages : 3518
Inscription : jeu. 22/janv./2004 14:31
Localisation : Sourans

Message par Anonyme2 »

Salut Eric,

Quand j'ai vu ton code, je me suis dit tout de suite que l'on allait avoir du mal à faire plus rapide :wink:
Je mets ma version mais la mienne est 2 fois plus lente pour une chaîne courte et 2,5 plus lente pour une chaîne hexa de 8 caractères.

Le codage dans la table est sûrement la solution la plus rapide pour la conversion.

On gardera le meilleur :D

Code : Tout sélectionner

Procedure.l HexaDecimalToDecimal(Chaine.s)
; calcul de la valeur décimale d'une chaîne hexa
; le principe est celui des additions successives des valeurs de chaque caractère hexa
; en fonction de sa position dans la chaîne
; par exemple le nombre hexa $A0 vaut en décimal 160

; La décomposition de $A0 est
; A : 10 * 16^1 = 10 * 16 = 160
; 0 : 0  * 16^0 = 0  * 1  = 0
; Total : 160 + 0 = 160
;
; A vaut 10 en décimal et ce caractère est transformé en valeur décimale 10
; La chaîne hexa mesure sans le $ 2 
; A étant le premier caractère hexa, il est à la position 2 dans la chaine en partant de la droite
;  mais sa puissance de 16 est de 2-1 (16^1)
; je charge dans la table la puissance de 16 précalculée
; par exemple 16^0 correspond la valeur située à l'adresse de la table +0
; par exemple 16^1 correspond la valeur située à l'adresse de la table + 1*4 (*4 car la valeur
; codée est une valeur 32 bits donc sur 4 octets)
; par exemple 16^3 correspond la valeur située à l'adresse de la table + 3*4
; je multiplie cette puissance par la valeur correspondante au caractère
; le tout est stocké dans eax auquel on ajoute ensuite l'ancienne valeur de eax, résultat
; des précédants calculs
valeur.l
      MOV ebx,Chaine
      CMP byte [ebx],'$'
      JNZ NonChaineHexa1

      MOV    ecx, 0                   ; ecx à 0
      INC    ebx                      ; on pointe après le $
      MOV    eax, ecx                 ; eax à 0
      LEA    esi, [PuissanceHexa]     ; esi = adresse de la 1er valeur de la table hexa
      PUSH   ebx                      ; sauvegarde afin de récupérer plus tard cette valeur
  
  ; calcul de la longueur de la chaine
    !Compte:
      MOV    dl, [ebx]
      TEST   dl, dl
      JZ     FinComptage
      INC    cl
      INC    ebx
      JMP    Compte

    !FinComptage:
      POP    ebx                   ; ebx = adresse du début de chaine après le $
      DEC    ecx                   ; ecx = exposant de la puissance du 1er caractère
      JS     NonChaineHexa1
      CMP    cl, 7                ; on termine si la chaine hexa > à 8 caractères
      JA     NonChaineHexa1

    !DebutCalcul:
      MOVZX  edx, byte [ebx]       ; dl = le caractère hexa
      TEST   dl, dl                ; si = 0 on quite, fin de chaine
      JZ     Finchaine

    !Minuscule?:
      CMP    dl, 'f'
      JA     NonChaineHexa1
      CMP    dl, 'a'
      JB     Majuscule?
      ADD    dl, -87               ; on ajuste pour partir à 10

    !Calcul:                       ; résultat dans eax à chaque tour de boucle
      PUSH   eax                   ; sauvegarde temporaire de eax
      MOV    eax, [esi+(ecx*4)]    ; la puissance de 16 correspondante à la position du caractère dans la chaine
      MUL    edx                   ; multiplication non signée de eax par edx, résultat dans eax
      POP    edx                   ; edx = ancienne valeur de eax
      ADD    eax, edx              ; eax = résultat
      INC    ebx                   ; incrémentation du pointeur de chaine
      DEC    ecx                   ; décrémentation de l'exposant de la puissance de 16
      JMP    DebutCalcul  
  
    !Majuscule?:  
      CMP    dl, 'F'
      JA     NonChaineHexa1
      CMP    dl, 'A'
      JB     Nombre?
      ADD    dl, -55               ; on ajuste pour partir à 10
      JMP    Calcul

    !Nombre?:  
      CMP    dl, '9'               
      JA     NonChaineHexa1        
      CMP    dl, '0'               
      JB     NonChaineHexa1        
      ADD    dl, -48               ; c'est un chiffre, on ajuste pour partir à 0 ('0' = 48)
      JMP    Calcul

    !Finchaine:
      ProcedureReturn 

    !PuissanceHexa:
      !DD    1, 16, 256, 4096, 65536, 1048576, 16777216, 268435456

    !NonChaineHexa1:
      ProcedureReturn 0

EndProcedure

Debug HexaDecimalToDecimal("$")
Debug HexaDecimalToDecimal("$10")
Debug HexaDecimalToDecimal("$1A0f")
Debug HexaDecimalToDecimal("10")
Debug HexaDecimalToDecimal("$1u0") 
Debug HexaDecimalToDecimal("$ABCDEF")
Debug HexaDecimalToDecimal("$abcdef")
Debug HexaDecimalToDecimal("$12345678")
Debug HexaDecimalToDecimal("$123456781")
Anonyme2
Messages : 3518
Inscription : jeu. 22/janv./2004 14:31
Localisation : Sourans

Message par Anonyme2 »

Eric,
j'ai légèrement modifié ton code et l'amélioration sur ma bécanne est de 1 % pour 500000 itérations pour une chaine hexa de 8 caractères et de moins de 2 % pour une chaine de 1 caractère , c'est faible.

Code : Tout sélectionner

Procedure ValHex1(Chaine.s)
          Valeur.l
          MOV ecx,Chaine
          CMP byte [ecx],'$'
          JNZ NonChaineHexa1
          !LEA ebx,[TableValeur1]
          MOV edx,0
          XOR eax,eax
          !Encore1:
                    INC ecx
                    MOV al,byte [ecx]
                    CMP al,0
                    JE FinChaineHexa1
                    XLATB
                    ADD  edx, edx    ; ajouté ça, edx = edx * 2
                    CMP al,$FF
                    JE NonChaineHexa1
                    LEA edx, [(edx*8)+eax]   ; ajouté ça, opération effectuée en 1 cycle d'horloge sur les pentium double pipeline
                  ;  ROL edx,4
                  ;  ADD edx,eax
                    JMP Encore1
          !FinChaineHexa1:
                    MOV Valeur,edx
                    ProcedureReturn Valeur
          !NonChaineHexa1:
          ProcedureReturn 0
          !TableValeur1:
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$0A,$0B,$0C,$0D,$0E,$0F,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$0A,$0B,$0C,$0D,$0E,$0F,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
EndProcedure
Anonyme2
Messages : 3518
Inscription : jeu. 22/janv./2004 14:31
Localisation : Sourans

Message par Anonyme2 »

Voilà pour le soldat inconnu, la fonction binaire en décimal sur 32 bits

2 versions, la première ne controle pas la longueur de la chaine, la seconde oui et retoure 0 si la chaine a plus de 32 caractères binaires (hormis le %) ou si la chaine en 0 (hormis le %)

Code : Tout sélectionner

Procedure.l BinaireToDecimal(Chaine.s)
; calcul de la valeur décimale d'une chaîne bianaire sur 32 bits
; le principe est celui des additions successives des valeurs de chaque caractère binaire
; en fonction de sa position dans la chaîne
; par exemple le nombre hexa %10 vaut en décimal 2

; La décomposition de %10 est
; 1 : 1 * 2^1 = 1 * 2 = 2
; 0 : 0 * 2^0 = 0  * 1  = 0
; Total : 2 + 0 = 2
;
; Le principe est de multipier le résultat précédant par 2 et d'ajouter 0 ou 1 en fonction du
; caractère binaire. Il est plus rapide de ne pas faire de test et d'ajouter la valeur même
; si cette valeur vaut 0
; La chaîne binaire mesure sans le $ a au max 32 caractères

; eax stocke le résultat
; ebx contient l'adresse de la chaine binaire
; edx reçoit les caractères de la chaine pour les tests
; le code ne contrôle pas le nombre de caractères de la chaîne

      MOV ebx,Chaine
      CMP byte [ebx],'%'
      JNZ NonChaineBinaire

      XOR eax, eax
      
    !DebutCalcul:
      INC    ebx                      ; incrémentation de l'adresse de la chaine
      MOVZX  edx, byte [ebx]          ; dl = le caractère binaire pointé par ebx
      TEST   dl, dl                   ; si = 0 on quitte, fin de chaine
      JZ     FinchaineBinaire
      ADD    dl, -'0'                 ; soustrait la valeur ASCII du 0
      JS     NonChaineBinaire         ; erreur si nombre négatif
      CMP    dl, 1                    
      JA     NonChaineBinaire         ; erreur si > 1
      LEA    eax, [eax*2+edx]         ; multiplication de eax par 2 puis ajout de edx, résultat
                                      ; dans eax
      JMP    DebutCalcul              ; on reboucle

    !NonChaineBinaire:
      MOV    eax, 0

    !FinchaineBinaire:
      ProcedureReturn

EndProcedure 

le second

Code : Tout sélectionner

Procedure.l BinaireToDecimal(Chaine.s)
      MOV    ebx,Chaine
      CMP    byte [ebx],'%'
      JNZ    NonChaineBinaire
      PUSH   ebx
      SUB    eax, eax    ; eax = 0

  ; calcul de la longueur de la chaine
    !Compte:
      INC    ebx        ; on passe le %
      MOV    dl, [ebx]
      TEST   dl, dl
      JZ     FinComptage
      INC    eax
      JMP    Compte

    !FinComptage:
      POP    ebx  
      CMP    eax, 32
      JA     NonChaineBinaire         ; on quitte si la chaine > 32 caractères
      TEST   eax, eax
      JZ     NonChaineBinaire         ; on quitte si la chaine = 0 caractère

      XOR eax, eax
      
    !DebutCalcul:
      INC    ebx                      ; incrémentation de l'adresse de la chaine
      MOVZX  edx, byte [ebx]          ; dl = le caractère binaire pointé par ebx
      TEST   dl, dl                   ; si = 0 on quitte, fin de chaine
      JZ     FinchaineBinaire
      ADD    dl, -'0'                 ; soustrait la valeur ASCII du 0
      JS     NonChaineBinaire         ; erreur si nombre négatif
      CMP    dl, 1                    
      JA     NonChaineBinaire         ; erreur si > 1
      LEA    eax, [eax*2+edx]         ; multiplication de eax par 2 puis ajout de edx, résultat
                                      ; dans eax
      JMP    DebutCalcul              ; on reboucle

    !NonChaineBinaire:
      MOV    eax, 0

    !FinchaineBinaire:
      ProcedureReturn

EndProcedure 
erix14
Messages : 480
Inscription : sam. 27/mars/2004 16:44
Contact :

Message par erix14 »

Salut Denis,
ajouté ça, opération effectuée en 1 cycle d'horloge sur les pentium double pipeline
Tu as de la documentation sur les cycles d'horloge des Pentium ?
Moi, j'ai maximum celui du 486. Et j'ai cherché sur Internet, mais n'est encore rien trouvé.
Anonyme2
Messages : 3518
Inscription : jeu. 22/janv./2004 14:31
Localisation : Sourans

Message par Anonyme2 »

erix14 a écrit :Salut Denis,
ajouté ça, opération effectuée en 1 cycle d'horloge sur les pentium double pipeline
Tu as de la documentation sur les cycles d'horloge des Pentium ?
Moi, j'ai maximum celui du 486. Et j'ai cherché sur Internet, mais n'est encore rien trouvé.
J'ai plusieurs livres sur l'asm ou certaines instructions sont parfois commentées pour l'optimisation. Pour LEA, 1 cycle est vrai si l'instruction précédante n'a pas pas modifié un des registres utilisé, sinon l'instruction prend 2 cycles.

Il me semble avoir lu qu'il a de la doc MS avec les cycles d'instruction, mais je n'en sait pas plus.

Il y a de la doc Intel sur l'optimisation mais je n'ai pas détaillé (en anglais)

La page Intel

http://developer.intel.com/design/penti ... ex_new.htm
Le Soldat Inconnu
Messages : 4312
Inscription : mer. 28/janv./2004 20:58
Localisation : Clermont ferrand OU Olsztyn
Contact :

Message par Le Soldat Inconnu »

j'ai supprimé la vérif du $ au début

Code : Tout sélectionner

Procedure HexVal(Hex.s)
  Protected Val.l
  MOV ecx, Hex
  LEA ebx, [TableValeurHex]
  MOV edx, 0
  MOV eax, 0
  ! EncoreChaineHex :
  MOV al, byte[ecx]
  CMP al, 0
  JE FinChaineHex
  XLATB
  CMP eax, $FF
  JE ErreurChaineHex
  ROL edx, 4
  ADD edx, eax
  INC ecx
  JMP EncoreChaineHex
  ! FinChaineHex :
  MOV Val, edx
  ProcedureReturn Val
  ! ErreurChaineHex :
  ProcedureReturn -1
  ! TableValeurHex :
  ! DB $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $FF, $FF, $FF, $00, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $00, $01, $02, $03, $04, $05, $06, $07, $08, $09, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $0A, $0B, $0C, $0D, $0E, $0F, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $0A, $0B, $0C, $0D, $0E, $0F, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
EndProcedure
et j'ai fait de même pour le binaire car ma sltuion visiblement plus simple est finallement pus lente (commparé avec les carac 0 et 1, sion erreur)

Code : Tout sélectionner

Procedure BinVal2(Bin.s)
  Protected Val.l
  MOV ecx, Bin
  LEA ebx, [TableValeurBin]
  MOV edx, 0
  MOV eax, 0
  
  ! EncoreChaineBin :
  MOV al, byte[ecx]
  CMP al, 0
  JE FinChaineBin
  XLATB
  CMP eax, $FF
  JE ErreurChaineBin
  ROL edx, 1
  ADD edx, eax
  INC ecx
  JMP EncoreChaineBin
  
  ! FinChaineBin :
  MOV Val, edx
  ProcedureReturn Val
  
  ! ErreurChaineBin :
  ProcedureReturn -1
  
  ! TableValeurBin :
  ! DB $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $FF, $FF, $FF, $FF, $00, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $00, $01, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
EndProcedure
Dernière modification par Le Soldat Inconnu le sam. 19/mars/2005 19:15, modifié 1 fois.
Je ne suis pas à moitié Polonais mais ma moitié est polonaise ... Vous avez suivi ?

[Intel quad core Q9400 2.66mhz, ATI 4870, 4Go Ram, XP (x86) / 7 (x64)]
Anonyme2
Messages : 3518
Inscription : jeu. 22/janv./2004 14:31
Localisation : Sourans

Message par Anonyme2 »

Le Soldat Inconnu a écrit :j'ai supprimé la vérif du $ au début

Code : Tout sélectionner

Procedure HexVal(Hex.s)
  Protected Val.l
  MOV ecx, Hex
  LEA ebx, [TableValeurHex]
  MOV edx, 0
  MOV eax, 0
  ! EncoreChaineHex :
  MOV al, byte[ecx]
  CMP al, 0
  JE FinChaineHex
  XLATB
  CMP eax, $FF
  JE ErreurChaineHex
  ROL edx, 4
  ADD edx, eax
  INC ecx
  JMP EncoreChaineHex
  ! FinChaineHex :
  MOV Val, edx
  ProcedureReturn Val
  ! ErreurChaineHex :
  ProcedureReturn -1
  ! TableValeurHex :
  ! DB $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $FF, $FF, $FF, $00, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $00, $01, $02, $03, $04, $05, $06, $07, $08, $09, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $0A, $0B, $0C, $0D, $0E, $0F, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $0A, $0B, $0C, $0D, $0E, $0F, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  ! DB $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
EndProcedure
Et le cahier des charges ? :D
Le Soldat Inconnu
Messages : 4312
Inscription : mer. 28/janv./2004 20:58
Localisation : Clermont ferrand OU Olsztyn
Contact :

Message par Le Soldat Inconnu »

ben moi, j'ai besoin de ne pas vérifier les $ ou % en début de mot ;)

en plus, tu avais mis une version sans vérif dan ton cahier des charges
Je ne suis pas à moitié Polonais mais ma moitié est polonaise ... Vous avez suivi ?

[Intel quad core Q9400 2.66mhz, ATI 4870, 4Go Ram, XP (x86) / 7 (x64)]
Anonyme2
Messages : 3518
Inscription : jeu. 22/janv./2004 14:31
Localisation : Sourans

Message par Anonyme2 »

Le Soldat Inconnu a écrit :ben moi, j'ai besoin de ne pas vérifier les $ ou % en début de mot ;)

en plus, tu avais mis une version sans vérif dan ton cahier des charges

J'ai fait ça ? :D
erix14
Messages : 480
Inscription : sam. 27/mars/2004 16:44
Contact :

Message par erix14 »

Denis, dis-moi si tu obtiens ( avec le code ci-dessous )
60 cycles d'horloge pour le code 1
et 52 cycle d'horloge pour le code 2

Code : Tout sélectionner

Structure LL 
          Low.l 
          High.l 
EndStructure 

Global Debut.LL,Fin.LL,CyclesHorlogeAVide.l,CyclesHorloge1.l,CyclesHorloge2.l,CyclesHorlogeTemp.l

CyclesHorlogeAVide = 999999999
CyclesHorloge1 = 999999999
CyclesHorloge2 = 999999999

MOV ecx,100000
!EncoreCycles:

!RDTSC 
MOV Debut\Low, eax
MOV Debut\High, edx
!RDTSC 
MOV Fin\Low, eax
MOV Fin\High, edx
!fild qword [v_Fin]
!fild qword [v_Debut]
!fsubp
!fistp dword[v_CyclesHorlogeTemp]
If CyclesHorlogeTemp < CyclesHorlogeAVide
          CyclesHorlogeAVide = CyclesHorlogeTemp
EndIf

!RDTSC 
MOV Debut\Low, eax
MOV Debut\High, edx
;/        code 1

ROL edx,4
ADD edx,eax 

ROL edx,4 
ADD edx,eax 

ROL edx,4 
ADD edx,eax 

ROL edx,4 
ADD edx,eax 

ROL edx,4 
ADD edx,eax 

ROL edx,4 
ADD edx,eax 

ROL edx,4 
ADD edx,eax 

ROL edx,4 
ADD edx,eax 

ROL edx,4 
ADD edx,eax 

ROL edx,4 
ADD edx,eax 

;/        fin code 1
!RDTSC 
MOV Fin\Low, eax
MOV Fin\High, edx
!fild qword [v_Fin]
!fild qword [v_Debut]
!fsubp
!fistp dword[v_CyclesHorlogeTemp]
If CyclesHorlogeTemp < CyclesHorloge1
          CyclesHorloge1 = CyclesHorlogeTemp
EndIf

!RDTSC 
MOV Debut\Low, eax
MOV Debut\High, edx
;/        code 2

ADD  edx, edx
LEA edx, [(edx*8)+eax]

ADD  edx, edx
LEA edx, [(edx*8)+eax]

ADD  edx, edx
LEA edx, [(edx*8)+eax]

ADD  edx, edx
LEA edx, [(edx*8)+eax]

ADD  edx, edx
LEA edx, [(edx*8)+eax]

ADD  edx, edx
LEA edx, [(edx*8)+eax]

ADD  edx, edx
LEA edx, [(edx*8)+eax]

ADD  edx, edx
LEA edx, [(edx*8)+eax]

ADD  edx, edx
LEA edx, [(edx*8)+eax]

ADD  edx, edx
LEA edx, [(edx*8)+eax]

;/        fin code 2
!RDTSC 
MOV Fin\Low, eax
MOV Fin\High, edx
!fild qword [v_Fin]
!fild qword [v_Debut]
!fsubp
!fistp dword[v_CyclesHorlogeTemp]
If CyclesHorlogeTemp < CyclesHorloge2
          CyclesHorloge2 = CyclesHorlogeTemp
EndIf

DEC ecx
JNZ EncoreCycles

message$ = "Cycles d'horloge code 1 : " + Str(CyclesHorloge1-CyclesHorlogeAVide) + Space(20) + Chr(13)
message$ = message$ + "Cycles d'horloge code 2 : " + Str(CyclesHorloge2-CyclesHorlogeAVide) + Chr(13)
MessageRequester("Vitesse ASM", message$, #MB_ICONINFORMATION) 
ce qui correspond à 6 cycles d'horloge pour

Code : Tout sélectionner

ROL edx,4
ADD edx,eax 
et 5,2 pour

Code : Tout sélectionner

ADD  edx, edx
LEA edx, [(edx*8)+eax]
Ce qui voudrait dire que LEA... ne fait pas 1 cycle d'horloge...
Anonyme2
Messages : 3518
Inscription : jeu. 22/janv./2004 14:31
Localisation : Sourans

Message par Anonyme2 »

Eric,

j'ai lancé ton code et j'ai la même valeur pour les 2 codes, 2280.

J'ai regardé à nouveau dans le bouquin de Michael Abrash, édition sybex, : Programmation graphique C/C++ Assembleur.

Pour LEA, sur pentium, mais pour d'autre instructions également, il y a les verrouillages du pipeline (AGI = Adress generation Interlock) qui peuvent ralentir les instructions.

Voici ce que dit le bouquin sur la règle de l'AGI
Si on modifie n'importe quelle partie d'un registre pendant un cycle, on ne peut pas utiliser ce registre pour adresser la mémoire pendant ce cycle ou le cycle suivant. (1 instruction est effectuée dans le pipeline U et l'instruction suivante est effectuée dans le pipeline V pendant le même cycle d'horloge et prend donc 1 cycle si la règle de l'AGI est respectée).

Si on effectue le code suivant, on perd 1 cycle d'établissement dans les pipelines)

Code : Tout sélectionner

ADD  edx, edx
LEA edx, [(edx*8)+eax] 
C'est pour ça que dans ton code que j'ai modifié j'ai placé le ADD edx, edx bien avant le LEA

Voici le code que j'ai utilisé pour comparer les vitesse sur celeron 2 Go.
J'ai refait des tests et je me suis rendu compte que je n'avais pas désactivé le débugger :roll:

Sans le débugger, le code avec le ROL est légèrement plus rapide pour une chaine courte et légèrement plus long pour une chaine longue, le tout pour moins de 1 %.

Le debugger a vraiment une grosse influence sur les tests.

Code : Tout sélectionner

Procedure ValHex(Chaine.s) 
          Valeur.l
          MOV ecx,Chaine
          CMP byte [ecx],'$'
          JNZ NonChaineHexa
          !LEA ebx,[TableValeur]
          MOV edx,0
          XOR eax,eax
          !Encore:
                    INC ecx
                    MOV al,byte [ecx]
                    CMP al,0
                    JE FinChaineHexa
                    XLATB
                    CMP al,$FF
                    JE NonChaineHexa
                    ROL edx,4
                    ADD edx,eax
                    JMP Encore
          !FinChaineHexa:
                    MOV Valeur,edx
                    ProcedureReturn Valeur
          !NonChaineHexa:
          ProcedureReturn 0
          !TableValeur:
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$0A,$0B,$0C,$0D,$0E,$0F,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$0A,$0B,$0C,$0D,$0E,$0F,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
EndProcedure
; 
Procedure ValHex1(Chaine.s)
          Valeur.l
          MOV ecx,Chaine
          CMP byte [ecx],'$'
          JNZ NonChaineHexa1
          !LEA ebx,[TableValeur1]
          MOV edx,0
          XOR eax,eax
          !Encore1:
                    INC ecx
                    MOV al,byte [ecx]
                    CMP al,0
                    JE FinChaineHexa1
                    XLATB
                    ADD edx, edx
                    CMP al,$FF
                    JE NonChaineHexa1
                    LEA edx, [edx*8+eax]
                   ; ROL edx,4
                   ; ADD edx,eax
                    JMP Encore
          !FinChaineHexa1:
                    MOV Valeur,edx
                    ProcedureReturn Valeur
          !NonChaineHexa1:
          ProcedureReturn 0
          !TableValeur1:
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$0A,$0B,$0C,$0D,$0E,$0F,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$0A,$0B,$0C,$0D,$0E,$0F,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
                    ! DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
EndProcedure
 
SetPriorityClass_(GetCurrentProcess_(),#HIGH_PRIORITY_CLASS )
Temps1 = ElapsedMilliseconds() 
For i = 1 To 50000000
    ValHex("$A0")
Next i

Temps2 = ElapsedMilliseconds()
For i = 1 To 50000000
   ValHex1("$A0")
Next i
 
Temps3 = ElapsedMilliseconds() 
SetPriorityClass_(GetCurrentProcess_(),#NORMAL_PRIORITY_CLASS)

MessageRequester("Test rapidité", "Solution 1 : " + Str(Temps2 - Temps1) + " ; Solution 2 : " + Str(Temps3 - Temps2) + Chr(10) + "Ratio = 1 / " + StrF((Temps2 - Temps1) / (Temps3 - Temps2)), 0)

SetPriorityClass_(GetCurrentProcess_(),#HIGH_PRIORITY_CLASS )
Temps1 = ElapsedMilliseconds() 
For i = 1 To 5000000
    ValHex("$ABCDEF19")
Next i

Temps2 = ElapsedMilliseconds()
For i = 1 To 5000000
    ValHex1("$ABCDEF19")
Next i
 
Temps3 = ElapsedMilliseconds() 
SetPriorityClass_(GetCurrentProcess_(),#NORMAL_PRIORITY_CLASS)

MessageRequester("Test rapidité", "Solution 1 : " + Str(Temps2 - Temps1) + " ; Solution 2 : " + Str(Temps3 - Temps2) + Chr(10) + "Ratio = 1 / " + StrF((Temps2 - Temps1) / (Temps3 - Temps2)), 0)
Répondre