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

x86 32-bits / 64-bits Assembleur Discussion :

Afficher un nombre contenu sur 128 bits


Sujet :

x86 32-bits / 64-bits Assembleur

  1. #1
    Membre à l'essai
    Inscrit en
    Avril 2009
    Messages
    11
    Détails du profil
    Informations forums :
    Inscription : Avril 2009
    Messages : 11
    Points : 15
    Points
    15
    Par défaut Afficher un nombre contenu sur 128 bits
    Bonjour,

    Je fais de l’assembleur sous linux (processeur x86) avec le compilateur NASM.
    J’écris un programme qui calcule différentes valeurs. Et dans celui-ci, j’aimerais afficher un nombre contenu sur 128 bits dans une variable.

    Mais le problème, c’est que je ne sais pas diviser ce nombre par 10, comme je le ferais pour un nombre de petite taille qui serait dans EAX et que je diviserais en faisant DIV EBX (EBX qui contiendrait 10). Ce qui me donnerait le quotient dans EAX et le reste dans EDX. J’ajoute ensuite 30h à EDX pour obtenir le code A.S.C.I.I. du chiffre. Et je fais cette opération jusqu’à ce que le quotient soit nul.

    Je cherche donc un autre moyen de convertir ce nombre en décimal afin de pouvoir l’afficher.

    Si quelqu’un a une idée à me proposer, ce serait sympa.

    Merci d’avance à ceux qui prendront le temps de me répondre.

  2. #2
    Membre actif

    Inscrit en
    Février 2009
    Messages
    200
    Détails du profil
    Informations forums :
    Inscription : Février 2009
    Messages : 200
    Points : 235
    Points
    235
    Par défaut
    Tu peux utiliser un algo de représentation scientifique de type 80 bits que tu adapteras à tes besoins octoword:
    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
     
    ;;
    This procedure was written by Raymond Filiatreault.
     
    This FloatToAscii function converts an 80-bit REAL number (Src) to its
    decimal representation as a zero terminated alphanumeric string which
    is returned at the specified memory destination unless an invalid
    operation is reported by the FPU. The format of the string can be 
    specified as regular, or scientific notation. The number of decimal
    places returned must also be specified but the total number of digits
    must not exceed 18.
     
    The source can be an 80-bit REAL number from the FPU itself or from
    memory. If the source is taken from the FPU, its value will be preserved
    there if no error is reported.
     
    The source is not checked for validity. This is the programmer's
    responsibility.
     
    This procedure is based on using an FPU instruction to convert the
    REAL number into a specific packed decimal format. After unpacking,
    the decimal point is positioned as required.
     
    Only EAX is used to return error or success. All other registers are
    preserved.
    ____________________________________________________________________________________________
    Calling: > call FloatToAscii Source, Destination, Decimal, FLAG
     
    Source: Either a Pointer to a Data [T$Source: ...], or &NULL if you 
    "fld F$ / R$ / T$ Source" before calling.
     
    Destination: Pointer to a Data Buffer for the Ascii String 
    (Max Size = 25 Bytes).
     
    Decimal: The Number of wanted decimals (Max = 15).
     
    FLAG (for notation choice): Either SCIENTIFIC or REGULAR.
    ____________________________________________________________________________________________
    ;;
    ; Flags:
    [REGULAR 0 SCIENTIFIC 1]
    Proc FloatToAscii:
    Arguments @Source, @Destination, @Decimal, @Flag
    Local @temporary, @eSize, @oldcw, @truncw, @stword
    Structure @BCD 12, @bcdstr 0
    fclex ;clear exception flags on FPU
    ; Get the specified number of decimals for result (MAX = 15):
    On D@Decimal > 0F, mov D@Decimal 0F
    ; The FPU will be initialized only if the source parameter is not taken
    ; from the FPU itself (D@ Source <> &NULL):
    .If D@Source = &NULL
    fld st0 ;copy it to preserve the original value
    .Else
    mov eax D@Source
    If eax > 0400_000
    finit | fld T$eax
    ; Check first if value on FPU is valid or equal to zero:
    ftst ;test value on FPU
    fstsw W@stword ;get result
    test W@stword 04000 ;check it for zero or NAN
    jz L0> ;continue if valid non-zero
    test W@stword 0100 ;now check it for NAN
    jnz L1> ;Src is NAN or infinity - cannot convert
    ; Here: Value to be converted = 0
    mov eax D@Destination | mov W$eax '0' ; Write '0', 0 szstring
    mov eax &TRUE | finit | ExitP
    Else
    L1: finit | mov eax &FALSE | ExitP
    End_If
    .End_If
    ; Get the size of the number:
    L0: fld st0 ;copy it
    fabs ;insures a positive value
    fld1 | fldl2t
    fdivp ST1 ST0 ;->1/[log2(10)]
    fxch | fyl2x ;->[log2(Src)]/[log2(10)] = log10(Src)
     
    fstcw W@oldcw ;get current control word
    mov ax W@oldcw
    or ax 0C00 ;code it for truncating
    mov W@truncw ax
    fldcw W@truncw ;change rounding code of FPU to truncate
     
    fist D@eSize ;store characteristic of logarithm
    fldcw W@oldcw ;load back the former control word
    ftst ;test logarithm for its sign
    fstsw W@stword ;get result
    test W@stword 0100 ;check if negative
    jz L0>
    dec D@eSize
     
    L0: On D@eSize > 15, mov D@Flag SCIENTIFIC
    ; Multiply the number by a power of 10 to generate a 16-digit integer:
    L0: fstp st0 ;get rid of the logarithm
    mov eax 15
    sub eax D@eSize ;exponent required to get a 16-digit integer
    jz L0> ;no need if already a 16-digit integer
    mov D@temporary eax
    fild D@temporary
    fldl2t | fmulp ST1 ST0 ;->log2(10)*exponent
    fld st0 | frndint | fxch
    fsub st0 st1 ;keeps only the fractional part on the FPU
    f2xm1 ;->2^(fractional part)-1
    fld1
    faddp ST1 ST0 ;add 1 back
    fscale ;re-adjust the exponent part of the REAL number
    fxch
    fstp st0
    fmulp ST1 ST0 ;->16-digit integer
    L0: fbstp T@bcdstr ;transfer it as a 16-digit packed decimal
    fstsw W@stword ;retrieve exception flags from FPU
    test W@stword 1 ;test for invalid operation
    jnz L1<< ;clean-up and return error
     
    ; Unpack bcd, the 10 bytes returned by the FPU being in the little-endian style:
    push ecx, esi, edi
    lea esi D@bcdstr+9
    mov edi D@Destination
    mov al B$esi ;sign byte
    dec esi | dec esi
    If al = 080
    mov al '-' ;insert sign if negative number
    Else
    mov al ' ' ;insert space if positive number
    End_If
    stosb
    ...If D@Flag = REGULAR 
    ; Verify number of decimals required vs maximum allowed:
    mov eax 15 | sub eax D@eSize
    cmp eax D@Decimal | jae L0>
    mov D@Decimal eax
     
    ; ;check for integer digits:
    L0: mov ecx D@eSize
    or ecx ecx ;is it negative
    jns L3>
    ; Insert required leading 0 before decimal digits:
    mov ax '0.' | stosw
    neg ecx
    cmp ecx D@Decimal | jbe L0>
    jmp L8>>
     
    L0: dec ecx | jz L0>
    stosb | jmp L0<
    L0:
    mov ecx D@Decimal | inc ecx
    add ecx D@eSize | jg L4>
    jmp L8>>
    ; Do integer digits:
    L3: inc ecx
    L0: movzx eax B$esi | dec esi | ror ax 4 | ror ah 4
    add ax '00' | stosw | sub ecx 2 | jg L0<
    jz L0>
    dec edi
     
    L0: cmp D@Decimal 0 | jz L8>>
    mov al '.' | stosb
    If ecx <> 0
    mov al ah | stosb
    mov ecx D@Decimal | dec ecx | jz L8>>
    Else
    mov ecx D@Decimal
    End_If
    ; Do decimal digits:
    L4: movzx eax B$esi
    dec esi
    ror ax 4 | ror ah 4 | add ax 03030 | stosw
    sub ecx 2 | jg L4<
    jz L1>
    dec edi
    L1: jmp L8>>
    ; scientific notation
    ...Else
    mov ecx D@Decimal | inc ecx
    movzx eax B$esi | dec esi
    ror ax 4 | ror ah 4 | add ax '00' | stosb
    mov al '.' | stosb
    mov al ah | stosb
    sub ecx 2 | jz L7>
    jns L0>
    dec edi | jmp L7>
    L0: movzx eax B$esi
    dec esi
    ror ax 4 | ror ah 4
    add ax '00' | stosw | sub ecx 2 | jg L0<
    jz L7>
    dec edi
    L7: mov al 'E' | stosb
    mov al '+', ecx D@eSize | or ecx ecx | jns L0>
    mov al '-' | neg ecx
    L0: stosb
    ; Note: the absolute value of the size could not exceed 4931
    mov eax ecx
    mov cl 100
    div cl ;->thousands & hundreds in AL, tens & units in AH
    push eax
    and eax 0FF ;keep only the thousands & hundreds
    mov cl 10
    div cl ;->thousands in AL, hundreds in AH
    add ax '00' ;convert to characters
    stosw ;insert them
    pop eax
    shr eax 8 ;get the tens & units in AL
    div cl ;tens in AL, units in AH
    add ax '00' ;convert to characters
    stosw ;insert them
    ...End_If
    L8: mov B$edi 0 ;string terminating 0
    pop edi, esi, ecx
    finit | mov eax &TRUE
    EndP

  3. #3
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 369
    Points : 23 623
    Points
    23 623
    Par défaut
    Il faut procéder par étapes successives, comme tu le ferais sur papier à l'école.

    1. Sur 128 bits, tu commences par les 32 bits de poids fort, les plus à gauche, tu les charges dans EAX et tu fais ta division avec DIV. Tu sauves ton résultat au début de ton buffer de sortie ;
    2. Tu remets ton reste dans EAX. Celui-ci est forcément inférieur à 10 et tient donc dans quatre bits. Tu le décales de 16 bits vers la gauche, et tu charges les 16 bits suivants du nombre à diviser dans ceux que tu viens de libérer avec un simple MOV AX,xxxxx. Ça revient à faire « descendre » les chiffres suivants ;
    3. Tu refais ta division. Ton résultat tiendra forcément dans 16 bits. Tu les accoles à la droite du résultat que tu avais obtenu avec un MOV xxxx,AX ;
    4. Tu boucles à l'étape 2 jusqu'à ce que tu aies atteint et divisé les derniers de tes 128 bits.


    C'est une simple application de l'arithmétique traditionnelle à un cas de figure précis. C'est important de savoir le faire et d'en avoir l'idée car les microprocesseurs suffisamment sophistiqués pour savoir faire une division restent peu nombreux.

  4. #4
    Membre actif

    Inscrit en
    Février 2009
    Messages
    200
    Détails du profil
    Informations forums :
    Inscription : Février 2009
    Messages : 200
    Points : 235
    Points
    235
    Par défaut
    Si tu n'as besoin que de représentations d'entiers sur 128 bits c'est effectivement, et de loin, la solution la plus simple et la plus efficace.

    Cependant, si tu travailles aussi avec des nombres décimaux (ce qui n'est pas le cas dans l'exemple que tu as proposé) tu devras préparer ta chaîne autrement.

  5. #5
    Membre à l'essai
    Inscrit en
    Avril 2009
    Messages
    11
    Détails du profil
    Informations forums :
    Inscription : Avril 2009
    Messages : 11
    Points : 15
    Points
    15
    Par défaut
    Merci à vous deux pour vos réponses,

    Merci Obsidian pour ton explication claire et simple, c’est exactement se que je cherchais.

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

Discussions similaires

  1. Calcul sur 128 bits
    Par helmis dans le forum Débuter
    Réponses: 7
    Dernier message: 28/08/2008, 11h18
  2. Réponses: 9
    Dernier message: 23/08/2007, 14h56
  3. Problème d'alignement sur 128 bits
    Par progfou dans le forum C++
    Réponses: 24
    Dernier message: 06/07/2007, 16h15
  4. Nombre de 128 bits
    Par Elendhil dans le forum Langage
    Réponses: 2
    Dernier message: 24/05/2007, 17h00
  5. Afficher le nombre d'enregistrement sur un état
    Par ludolan dans le forum IHM
    Réponses: 1
    Dernier message: 14/12/2006, 16h45

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