You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 18:05:19