浮点到StrDec

时间:2017-05-30 21:57:50

标签: assembly masm fpu

我正在MASM Assembly上使用FP IEEE-754到StrDec。它工作正常,尽管我花了一些时间搞清楚这一点,但我不确定如何在逗号后添加更多数字 - 现在有两个,如123.46,但我需要123.456789。我想我确实需要一个计数器来处理我的额外位,但我得到access violation,同时在逗号之后添加额外的数字并增加字节数。

.data
     CaptionOut BYTE "Result: ", 0

    temp_bcd     dt   ?
    szdecimal    db   32 dup(0)

    MyNum REAL10 123.456789

.code
main PROC


    ; FPU to DecStr

   fld MyNum

   pushd 100            ;use the stack as storage for this value
   fimul dword ptr[esp] ;converts 2 decimal places as 2 more integer digits
   fbstp temp_bcd       ;store the packed BCD integer value
   pop  eax             ;clean the stack of the pushed 100 

; ESI will be used for pointing to the packed BCD
; EDI will be used for pointing to the decimal string

   push esi
   push edi
   lea  esi,temp_bcd+9  ;point to the most significant byte
   lea  edi,szdecimal   ;point to the start of the decimal string buffer
   xor  eax,eax
   fwait                ;to ascertain that the transfer of the
                        ;packed BCD is completed

   mov  al,[esi]        ;get the byte with the sign code
   dec  esi             ;decrement to next most significant byte
   or   al,al           ;for checking the sign bit
   jns  @F              ;jump if no sign bit
   mov  al,"-"          ;the value is negative
   stosb                ;insert the negative sign

@@:

; The next 8 bytes (in this example) will contain the integer digits
; and the least significant byte will then contain the 2 decimal digits.
; No leading 0 will be included in the integer portion
; unless it would be the only integer digit.

   mov  ecx,8           ;number of bytes to process for integer digits

@@:

   mov  al,[esi]        ;get the next byte
   dec  esi             ;adjust the pointer to the next one
   or   al,al           ;for checking if it is 0
   jnz  @F              ;the starting integer digit is now in AL
   dec  ecx             ;adjust the counter of integer bytes
   jnz  @B              ;continue searching for the first integer digit

; If the loop terminates with ECX=0, the integer portion would be 0.
; A "0" character must be inserted before processing the decimal digits

   mov  al,"0"          ;the ASCII 0
   stosb                ;insert it
   mov  al,[esi]        ;get the byte containing the decimal digits
   jmp  decimal_digits

@@:

; The first integer byte must be checked to determine
; if it contains 1 or 2 integer digits

   test al,0f0h         ;test if the H.O. nibble contains a digit
   jz   int_digit2      ;if not, process only the L.O. nibble

int_digit1:
   ror  ax,4            ;puts the H.O. nibble in the L.O. nibble position
                        ;and saves the L.O. nibble in AH
   add  al,30h          ;convert it to ASCII character
   stosb                ;store this character
   shr  ax,12           ;restores the L.O. nibble in AL
                        ;and also resets the other bits of AX

int_digit2:
   add  al,30h          ;convert it to ASCII character
   stosb                ;store this character
   mov  al,[esi]        ;get next byte
   dec  esi             ;adjust the pointer to the next one
   dec  ecx             ;adjust the counter of integer bytes
   jnz  int_digit1      ;continue processing the integer bytes

decimal_digits:
   mov  byte ptr [edi],"." ;insert the preferred decimal delimiter
   inc  edi

; Also, if the number of required decimal digits is not even, the code
; would have to be altered to insert the decimal delimiter at the
; proper location.

   ror  ax,4            ;puts the H.O. nibble in the L.O. nibble position
                        ;and saves the L.O. nibble in AH
   add  al,30h          ;convert it to ASCII character
   stosb                ;store this character
   shr  ax,12           ;restores the L.O. nibble in AL
                        ;and also resets the other bits of AX
   add  al,30h          ;convert it to ASCII character
   stosw                ;store this character + the terminating 0

   INVOKE MessageBoxA, 0, ADDR szdecimal, ADDR CaptionOut, 0

    INVOKE ExitProcess,0
main ENDP
END main

感谢您的帮助或想法!

1 个答案:

答案 0 :(得分:1)

您无需引入新计数器。您正在通过递减temp_bcd从下到上解析ESI。如果ESI位于temp_bcd开始之前的地址,则解析已结束。一个小问题是你在加载ESI后递减AL。所以最后一个(正确的)AL意味着一个(不正确的)ESI beyound the boarder。因此ESI必须小于2个字节才能打破循环。

对于逗号后的六个数字,您必须将MyNum乘以1.000.000并将ECX更改为6(目前为8)。

INCLUDE masm32rt.inc

.data
     CaptionOut BYTE "Result: ", 0

     temp_bcd     dt     ?
     szdecimal    db     32 dup(0)

     MyNum REAL10 123.456789

.code
main PROC


    ; FPU to DecStr

    fld MyNum

;   pushd 100               ;use the stack as storage for this value
    pushd 1000000               ;use the stack as storage for this value
    fimul dword ptr[esp] ;converts 2 decimal places as 2 more integer digits
    fbstp temp_bcd          ;store the packed BCD integer value
    pop  eax                    ;clean the stack of the pushed 100

; ESI will be used for pointing to the packed BCD
; EDI will be used for pointing to the decimal string

    push esi
    push edi
    lea  esi,temp_bcd+9 ;point to the most significant byte
    lea  edi,szdecimal  ;point to the start of the decimal string buffer
    xor  eax,eax
    fwait                       ;to ascertain that the transfer of the
                                ;packed BCD is completed

    mov  al,[esi]           ;get the byte with the sign code
    dec  esi                    ;decrement to next most significant byte
    or    al,al             ;for checking the sign bit
    jns  @F                 ;jump if no sign bit
    mov  al,"-"             ;the value is negative
    stosb                       ;insert the negative sign

@@:

; The next 8 bytes (in this example) will contain the integer digits
; and the least significant byte will then contain the 2 decimal digits.
; No leading 0 will be included in the integer portion
; unless it would be the only integer digit.

;   mov  ecx,8              ;number of bytes to process for integer digits
    mov  ecx,6              ;number of bytes to process for integer digits

@@:

    mov  al,[esi]           ;get the next byte
    dec  esi                    ;adjust the pointer to the next one
    or    al,al             ;for checking if it is 0
    jnz  @F                 ;the starting integer digit is now in AL
    dec  ecx                    ;adjust the counter of integer bytes
    jnz  @B                 ;continue searching for the first integer digit

; If the loop terminates with ECX=0, the integer portion would be 0.
; A "0" character must be inserted before processing the decimal digits

    mov  al,"0"             ;the ASCII 0
    stosb                       ;insert it
    mov  al,[esi]           ;get the byte containing the decimal digits
    jmp  decimal_digits

@@:

; The first integer byte must be checked to determine
; if it contains 1 or 2 integer digits

    test al,0f0h            ;test if the H.O. nibble contains a digit
    jz    int_digit2        ;if not, process only the L.O. nibble

int_digit1:
    ror  ax,4               ;puts the H.O. nibble in the L.O. nibble position
                                ;and saves the L.O. nibble in AH
    add  al,30h             ;convert it to ASCII character
    stosb                       ;store this character
    shr  ax,12              ;restores the L.O. nibble in AL
                                ;and also resets the other bits of AX

int_digit2:
    add  al,30h             ;convert it to ASCII character
    stosb                       ;store this character
    mov  al,[esi]           ;get next byte
    dec  esi                    ;adjust the pointer to the next one
    dec  ecx                    ;adjust the counter of integer bytes
    jnz  int_digit1     ;continue processing the integer bytes

decimal_digits:
    mov  byte ptr [edi],"." ;insert the preferred decimal delimiter
    inc  edi

; Also, if the number of required decimal digits is not even, the code
; would have to be altered to insert the decimal delimiter at the
; proper location.

;   ror  ax,4               ;puts the H.O. nibble in the L.O. nibble position
                                ;and saves the L.O. nibble in AH
;   add  al,30h             ;convert it to ASCII character
;   stosb                       ;store this character
;   shr  ax,12              ;restores the L.O. nibble in AL
                                ;and also resets the other bits of AX
;   add  al,30h             ;convert it to ASCII character
;   stosw                       ;store this character + the terminating 0

@@:
    ror  ax,4            ;puts the H.O. nibble in the L.O. nibble position
                        ;and saves the L.O. nibble in AH
    add  al,30h          ;convert it to ASCII character
    stosb                ;store this character
    shr  ax,12           ;restores the L.O. nibble in AL
                        ;and also resets the other bits of AX
    add  al,30h          ;convert it to ASCII character
    stosb                ;store this character + the terminating 0

    mov  al,[esi]        ;get next byte
    dec  esi             ;adjust the pointer to the next one
    cmp esi, OFFSET temp_bcd - 1
    jae @B

    @@:
    mov BYTE PTR [edi], 0

    INVOKE MessageBoxA, 0, ADDR szdecimal, ADDR CaptionOut, 0

    INVOKE ExitProcess,0
main ENDP
END main

而且 - 当然 - 我会做的很不一样:https://stackoverflow.com/a/30133492/3512216: - )