YASM 8086浮点数区间判断函数异常问题排查
问题分析
我需要编写一个程序过滤输入文件的文本行,每行分为6列,列间以分号分隔。已实现3个过滤规则:
- 第二列不得包含字母u或v;
- 第三列数字的各位之和需等于7;
- 最后一列的两位小数需属于区间[2.34, 4.50]。
输入示例
B11;one;16;0;55;2.44 C1;two;43;0;17;3.77 D2;three;47;0;15;5.41
预期输出
B11;one;16;0;55;2.44 C1;two;43;0;17;3.77 6.21
我实现了判断最后一列数值是否在区间内的函数procBelongsToInterval(已更新),同时需将符合条件的数值求和,但该函数工作异常,请问可能的问题是什么?
相关函数代码
procBelongsToInterval函数
;[2.34, 4.50] procBelongsToInterval push ax xor ax, ax xor si, si ; saving floating point number digits to the buffer (without '.') .read mov al, [di] inc di cmp al, '-' je .break cmp al, '.' je .read cmp al, 32 jb .setToZero mov [doubleNumbers+si], al inc si jmp .read ; used si as a pointer to the next byte so have to set si to zero again .setToZero xor si, si jmp .first ; checking if number is in the bounds [2.34, 4.50] .first: mov al, [doubleNumbers+si] inc si cmp al, '2' je .firstBound cmp al, '3' je .belongs cmp al, '4' je .secondBound jmp .break .firstBound: mov al, [doubleNumbers+si] inc si cmp al, '3' jb .break ja .belongs mov al, [doubleNumbers+si] inc si cmp al, '4' jae .belongs jb .break .secondBound: mov al, [doubleNumbers+si] inc si cmp al, '5' ja .break jb .belongs mov al, [doubleNumbers+si] inc si cmp al, '0' je .belongs ja .break ; number belongs to the interval .belongs: mov [numberBelongsToInterval], byte 1 ; boolean value mov si, 3 mov [doubleNumbers+si], byte 0 mov [bytesRead2], si ; saving number of read bytes mov dx, doubleNumbers call procParseInt16 ; Extracts an integer of type int16 from the buffer whose address is DX. ; Function saves result into AX register add [suma], ax ; Adding sum with value in AX jmp .end .break: mov [numberBelongsToInterval], byte 0 jmp .end .end: pop ax ret
procParseInt16函数
procParseInt16: push dx push cx push si push di mov bx, dx mov ax, 0 mov si, 0 ; number of digits mov cl, 0 ; 0 - if nonnegative, 1 - otherwise ; eating spaces: .leading_spaces: cmp [bx], byte ' ' jne .next1 inc bx jmp .leading_spaces .next1: cmp [bx], byte 0 ; the end of the string? jne .next2 jmp .endParsing .next2: cmp [bx], byte '-' ; the minus jne .digits mov cl, 1 ; negative number inc bx .digits: cmp [bx], byte '0' jb .lessThanNumeric cmp [bx], byte '9' jbe .updateAX .lessThanNumeric: jmp .endParsing .updateAX: mov dx, 10 mul dx mov dh, 0 mov dl, [bx] sub dl, '0' add ax, dx inc si inc bx jmp .digits .endParsing: cmp si, 0 ; empty string? je .setErrorAndReturn clc cmp cl, 1 je .negateAndReturn jmp .return .negateAndReturn: neg ax jmp .return .setErrorAndReturn: stc .return: pop di pop si pop cx pop dx ret
procInt16ToStr函数
procInt16ToStr: ; Converts value from AX to ASCIIZ (decimal system) ; AX - int16 value ; DX - adress, where the result is placed push di push si push cx push bx push dx mov bx, dx mov cx, 0 mov si, 0 cmp ax, word 0 jge .next mov cl, 1 mov [bx], byte '-' inc bx neg ax .next: mov dx, 0 mov di, 10 div di add dl, '0' mov [bx], dl inc bx inc si cmp ax, 0 je .setSign jmp .next .setSign: .reverse: ; inc bx mov [bx], byte 0 ; asciiz dec bx pop dx push dx mov di, dx cmp cl, 1 jne .Ok inc di .Ok: mov ax, si shr ax, 1 mov cx, ax cmp cx, 0 je .return .loopByDigits: mov al, [di] mov ah, [bx] mov [di], ah mov [bx], al dec bx inc di loop .loopByDigits .return: pop dx pop bx pop cx pop si pop di ret
问题排查与原因分析
1. 求和逻辑的单位错误
你把两位小数当成整数相加(比如2.44存成244,3.77存成377,相加得621),但最终输出需要除以100得到6.21,当前代码完全没处理这个缩放步骤:
procBelongsToInterval直接把解析后的整数加到suma里,后续procInt16ToStr输出的是621,而非预期的6.21。
2. 区间判断的边界漏洞
- 在
.firstBound分支中,若输入是2.340这类超过两位小数的数值,代码会读取前三位数字,但原需求限定是两位小数,这里没有限制输入格式,可能导致误判; - 在
.secondBound分支中,若输入是4.5(一位小数),代码读取完'4'和'5'后,会尝试读取第三位,但此时已到行尾(ASCII码小于32),会读取到垃圾数据,进而判断错误。
3. 缓冲区处理的潜在问题
.read循环中,判断al < 32就跳转到.setToZero,但只有.belongs分支会手动设置doubleNumbers缓冲区以0结尾,其他分支跳出时缓冲区可能未正确终止,后续复用缓冲区会出现异常。
4. 寄存器保存违规
procBelongsToInterval修改了di寄存器,但没有提前push di、结束时pop di——di属于调用者保存寄存器,直接修改会破坏调用者的di值,导致后续列解析出错。
内容的提问来源于stack exchange,提问作者user10203585
相关产品推荐
相关产品推荐

