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

YASM 8086读取文件字符串并按第六列排序的实现困境

解决方案:YASM 8086 实现最后10条记录按第6列排序

核心思路

8086原生浮点操作复杂度高,先把第6列的[-9.99;9.99]实数缩放为整数(乘以100),比如9.99转成999,-9.99转成-999,用整数排序替代浮点排序简化逻辑。再用冒泡排序(适合10个元素的小规模场景)对保存的行指针和缩放后的值排序,最后按排序后的顺序输出整行到新文件。

步骤1:实数转缩放整数(补全预处理逻辑)

假设你已将第6列字符串读取到缓冲区,以下是转换代码:

; 输入:DS:SI 指向第6列字符串(如 "-3.14" 或 "5.00")
; 输出:AX = 缩放后的整数(-314 或 500)
convert_real_to_scaled:
    xor ax, ax          ; 初始化结果为0
    xor bx, bx
    mov bl, 1           ; 符号标记:1正/-1负
    mov cx, 0           ; 小数位数计数器

    ; 处理符号位
    cmp byte [si], '-'
    jne .positive
    mov bl, -1
    inc si
.positive:

    ; 处理整数部分
.next_int_digit:
    cmp byte [si], '.'
    je .decimal_part
    cmp byte [si], 0    ; 假设字符串以0终止
    je .end_convert
    sub byte [si], '0'
    mov dl, [si]
    mov dx, ax
    mov ax, 10
    mul dx              ; AX = AX * 10
    add ax, dl          ; AX += 当前数字
    inc si
    jmp .next_int_digit

.decimal_part:
    inc si
.next_dec_digit:
    cmp cx, 2           ; 最多取两位小数
    je .end_convert
    cmp byte [si], 0
    je .pad_zero
    sub byte [si], '0'
    mov dl, [si]
    mov dx, ax
    mov ax, 10
    mul dx
    add ax, dl
    inc si
    inc cx
    jmp .next_dec_digit

.pad_zero:
    ; 不足两位小数补0
    cmp cx, 2
    je .end_convert
    mov dx, ax
    mov ax, 10
    mul dx
    inc cx
    jmp .pad_zero

.end_convert:
    ; 应用符号
    mov dx, ax
    mov ax, bx
    mul dx              ; AX = AX * 符号值
    ret

步骤2:冒泡排序实现(针对10个行条目)

先定义存储行信息的结构体,再实现排序:

; 行条目结构体:存储行指针和缩放后的值
struc RowEntry
    .ptr        resd 1   ; 行内存地址(段+偏移,32位)
    .scaled_val resw 1   ; 缩放后的整数值
endstruc

; 假设已初始化数组:RowEntry row_list[10]

; 对row_list按.scaled_val升序排序
sort_row_list:
    mov cx, 9           ; 外层循环次数:n-1
.outer_loop:
    mov si, 0           ; 数组起始偏移
    mov bx, cx          ; 内层循环次数:n-1-i
.inner_loop:
    ; 比较相邻元素的缩放值
    mov ax, [row_list + si + RowEntry.scaled_val]
    cmp ax, [row_list + si + RowEntry_size + RowEntry.scaled_val]
    jle .no_swap        ; 当前值<=下一个值,不交换

    ; 交换两个RowEntry的内容
    ; 交换32位行指针
    mov dx, [row_list + si + RowEntry.ptr]
    mov bp, [row_list + si + RowEntry.ptr + 2]
    xchg dx, [row_list + si + RowEntry_size + RowEntry.ptr]
    xchg bp, [row_list + si + RowEntry_size + RowEntry.ptr + 2]
    mov [row_list + si + RowEntry.ptr], dx
    mov [row_list + si + RowEntry.ptr + 2], bp

    ; 交换16位缩放值
    xchg ax, [row_list + si + RowEntry_size + RowEntry.scaled_val]
    mov [row_list + si + RowEntry.scaled_val], ax

.no_swap:
    add si, RowEntry_size
    dec bx
    jnz .inner_loop

    dec cx
    jnz .outer_loop
    ret

步骤3:排序后输出到新文件

假设输出文件句柄已存在于BX中:

; 遍历排序后的数组,输出每行到文件
output_sorted_rows:
    mov cx, 10
    mov si, 0
.output_loop:
    ; 获取行地址:ES:DI = 行的段+偏移
    mov di, [row_list + si + RowEntry.ptr]
    mov es, [row_list + si + RowEntry.ptr + 2]

    ; 查找换行符,计算行长度(假设行以0x0A结尾)
    mov bp, di
.find_newline:
    cmp byte [es:bp], 0x0A
    je .found_newline
    inc bp
    jmp .find_newline
.found_newline:
    sub bp, di
    inc bp              ; 包含换行符的总长度

    ; DOS写文件调用:AH=0x40
    push ds
    mov ds, es
    mov dx, di
    mov ah, 0x40
    int 0x21
    pop ds

    add si, RowEntry_size
    dec cx
    jnz .output_loop
    ret

注意事项

  • 若需降序排序,只需把冒泡排序中的jle .no_swap改为jge .no_swap。
  • 确保行指针存储了正确的段和偏移地址,8086内存寻址需注意分段逻辑。
  • 如果你使用8087浮点协处理器,也可直接比较浮点值,但缩放整数的方法更适配无协处理器环境,代码更简洁。

内容的提问来源于stack exchange,提问作者gailtye

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 07:50:48