2017-05-30 31 views
0

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

.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

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