x86汇编中如何支持大整数输入?MyReadInt处理4000000007失败
修改x86汇编MyReadInt以支持大整数输入
我编写了一个x86汇编程序,功能是接收非负整数并判断其是否为素数,但输入4000000007时程序返回TryAgain错误。排查后发现问题出在MyReadInt过程——它仅能处理32位范围内的无符号整数,无法支持更大的数值输入,现需要修改该过程以支持更大的整数。
原代码片段如下:
INCLUDE Irvine32.inc .DATA startTime DWORD ? enter1 BYTE "Enter a non-negative integer (0 to exit): ",0 tryAgain BYTE "That input is not allowed. Try again.",0 prime BYTE " is a prime number.",0 notPrime BYTE " is not a prime number; it is divisible by: ",0 exitMessage BYTE "Goodbye",0 time BYTE "Procedure runtime in milliseconds: ",0 LMAX_DIGITS = 80 Linputarea BYTE LMAX_DIGITS dup(0),0 overflow_msgL BYTE " <32-bit integer overflow>",0 invalid_msgL BYTE " ",0 neg_msg BYTE " ",0 .code main PROC beginning: mov edx, OFFSET enter1 call WriteString ; writes null-terminated string to standard output call MyReadInt ; input stored in eax cmp eax, 0 ; compares eax to 0 jge noError ; continue if input >= 0 mov edx, OFFSET tryAgain ; if number is negative, write error message call WriteString ; writes null-terminated string to standard output jmp beginning ; loop beginning noError: ; 此处省略素数判断逻辑(原代码未完整给出) jmp beginning main ENDP ; end of procedure ;______________________________________________________________________________ ; MyReadInt PROC ; Modified from Irvine32.asm by _________ ; Reads a 32-bit unsigned decimal integer from standard ; input, stopping when the Enter key is pressed. ; All valid digits occurring before a non-numeric character ; are converted to the integer value. Leading spaces are ; ignored, and an optional leading + sign is permitted. ; Receives: nothing ; Returns: If CF=0, the integer is valid, and EAX = binary value. ; If CF=1, the integer is invalid and EAX = 0. ;______________________________________________________________________________ MyReadInt PROC uses ebx ecx edx esi ; Input a string of digits using ReadString. mov edx,offset Linputarea mov esi,edx ; save offset in ESI mov ecx,LMAX_DIGITS call ReadString mov ecx,eax ; save length in ECX cmp ecx,0 ; greater than zero? jne L1 ; yes: continue mov eax,0 ; no: set return value jmp L9 ; and exit ; Skip over any leading spaces. L1: mov al,[esi] ; get a character from buffer cmp al,' ' ; space character found? jne L2 ; no: check for a sign inc esi ; yes: point to next char loop L1 jcxz L8 ; quit if all spaces ; Check for a leading sign. L2: cmp al,'-' ; minus sign found? jne L3 ; no: look for plus sign mov edx, offset neg_msg ; tell user negative numbers not allowed jmp L8 L3: cmp al,'+' ; plus sign found? jne L4 ; no: must be a digit inc esi ; yes: skip over the sign dec ecx ; subtract from counter ; Test the first digit, and exit if it is nonnumeric. L3A:mov al,[esi] ; get first character call IsDigit ; is it a digit? jnz L7A ; no: show error message ; Start to convert the number. L4: mov eax,0 ; clear accumulator mov edx,0 ; 新增:清空64位累加器的高32位 mov ebx,10 ; EBX is the multiplier ; Repeat loop for each digit. L5: mov cl,[esi] ; 改用CL存储当前字符,避免占用EDX cmp cl,'0' ; character < '0'? jb L10 cmp cl,'9' ; character > '9'? ja L10 and ecx,0Fh ; convert to binary digit (存于CL) ; 先检查当前64位值乘以10后是否会溢出 ; 64位最大值0xFFFFFFFFFFFFFFFF,除以10得0x1999999999999999 cmp edx, 0x19999999 ja L6 ; EDX > 0x19999999,乘以10必溢出 jb MultiplyTen ; EDX < 0x19999999,可安全乘10 ; EDX == 0x19999999,检查EAX是否超过0x99999999 cmp eax, 0x99999999 ja L6 ; EAX > 0x99999999,乘10后溢出 MultiplyTen: ; 计算EDX:EAX = EDX:EAX * 10 push ecx ; 保存当前数字 mov ecx, ebx ; ECX = 10 mul ecx ; EDX:EAX = EAX * 10 pop ecx ; 恢复数字 ; 加上当前数字 add eax, ecx adc edx, 0 ; 处理进位到EDX inc esi ; point to next digit jmp L5 ; get next digit ; Carry out of 64 bits has occured, choose "integer overflow" messsage. L6: mov edx,OFFSET overflow_msgL ; 可将overflow_msgL修改为" <64-bit integer overflow>"以明确提示 jmp L8 ; Choose "invalid integer" message. L7A:mov edx,OFFSET invalid_msgL ; Display the error message pointed to by EDX. L8: call WriteString call Crlf mov eax,0 ; set return value to zero mov edx,0 ; 清空高32位 L9: stc ; set Carry flag to indicate error ret L10: clc ; clear Carry flag to indicate success ret MyReadInt ENDP END main
修改说明
- 扩展为64位存储:将原32位累加器EAX扩展为EDX:EAX组合的64位累加器,最大可支持到
18446744073709551615(2^64-1)的无符号整数,完全覆盖4000000007这类数值。 - 溢出判断优化:在乘以10前先检查当前64位值是否超过64位最大值除以10的阈值,提前拦截溢出情况,避免计算后的数据损坏。
- 寄存器调整:改用CL存储当前读取的字符,避免占用作为累加器高32位的EDX。
- 进位处理:在加上当前数字后,使用
adc edx,0处理可能产生的进位到高32位EDX,保证64位数值的正确性。
内容的提问来源于stack exchange,提问作者Caroline Warner
相关产品推荐
相关产品推荐

