【问题标题】:Floating Point to StrDec浮点数到 StrDec
【发布时间】:2017-05-30 21:57:49
【问题描述】:

我正在研究 FP IEEE-754 到 MASM 组装的 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

感谢任何帮助或想法!

【问题讨论】:

    标签: assembly masm fpu


    【解决方案1】:

    您无需引入新计数器。您通过递减ESI 从下到上解析temp_bcd。如果ESI 位于temp_bcd 开始之前的地址,则解析结束。一个小问题是你在加载AL 后递减ESI。所以最后一个(正确的)AL 暗示了一个(不正确的)ESI 在边界之外。所以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 :-)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-02
      • 1970-01-01
      • 2011-07-23
      • 2013-08-30
      • 1970-01-01
      • 2020-07-26
      • 2016-11-06
      • 1970-01-01
      相关资源
      最近更新 更多