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

8086汇编实现曼德博集合渲染结果不符,请求技术排查

曼德博集合渲染错误排查(8086汇编 + DOSBox)

作业要求回顾

  • 采用scale=64的定点数,禁止使用栈
  • 25×80屏幕单元格对应复点c = c_x + i*c_y,其中:
    • c_x = -144 + col * 3(0≤col≤79)
    • c_y = -72 + row * 6(0≤row≤24)
  • 迭代公式:z_{n+1} = z_n² + c,简化为定点数计算:
    x_new = (x² - y²)/64 + c_x
    y_new = (x*y)/32 + c_y
    
  • 最多迭代16次,逃逸条件:(x² + y²)/64 > 256(即x_sqr + y_sqr > 256)
  • 输出规则:
    • 1-3次逃逸:012Eh
    • 4-7次逃逸:042Ah
    • 8-15次逃逸:0EDBh
    • 16次未逃逸:0ADBh

用户提供的汇编代码

.model small
.stack 100h
.data
    ; We store our variables in memory because the 8086 processor 
    ; does not have enough registers to hold everything at once.
    c_x     dw 0    
    c_y     dw 0
    x       dw 0
    y       dw 0
    x_sqr   dw 0
    y_sqr   dw 0
    row_cnt dw 0
    col_cnt dw 0
    iter    dw 0

.code
START:
    ; clearing the dos screen
    mov ax, 0003h
    int 10h
    
    ; writing to the data segment our screen coordinates for the horizontal axis and setting di=0
    mov ax, @data
    mov ds, ax
    mov ax, 0B800h
    mov es, ax
    mov di, 0

    ; setting up the row loop
    mov c_y, -72
    mov row_cnt, 25

ROW_LOOP:
    ; setting up the colum loop
    mov c_x, -144
    mov col_cnt, 80

COL_LOOP:
    ; initial values of x,y from z_0
    mov x, 0
    mov y, 0
    mov iter, 1

MANDEL_LOOP:
    ; calculating x^2/64
    mov ax, x
    imul x              ; DX:AX = x * x
    mov bx, 64
    idiv bx             ; AX = (DX:AX) / 64
    mov x_sqr, ax       

    ; calculating y^2/64
    mov ax, y
    imul y              ; DX:AX = y * y
    mov bx, 64
    idiv bx             ; AX = (DX:AX) / 64
    mov y_sqr, ax       

    ; escape condition
    mov bx, x_sqr
    add bx, y_sqr
    cmp bx, 256         
    jg DRAW_PIXEL       

    ; compare iter to see the iter num of the iterated calc of z_n
    cmp iter, 16
    je DRAW_PIXEL       

    ; calc saving y_new = (xy) / 32 + c_y
    mov ax, x
    imul y              ; DX:AX = x * y
    mov bx, 32
    idiv bx             ; AX = (DX:AX) / 32
    add ax, c_y
    mov y, ax

    ; calc saving x_new = x_sqr - y_sqr + c_x
    mov ax, x_sqr
    sub ax, y_sqr
    add ax, c_x
    mov x, ax                   

    inc iter
    jmp MANDEL_LOOP

WRITE_VRAM:
    ; printing to the screen the char
    mov es:[di], ax     
    add di, 2           ; move forward 2 bytes in video memory

    ; moving to next colum
    add c_x, 3          
    dec col_cnt
    jz COL_DONE
    jmp COL_LOOP
COL_DONE:
    ; moving to next row

    add c_y, 6          
    dec row_cnt
    jz ROW_DONE
    jmp ROW_LOOP
ROW_DONE:

    jmp EXIT

DRAW_PIXEL:
    ; assigning the printed char based of iter value
    cmp iter, 3
    jle COL_1_3
    cmp iter, 7
    jle COL_4_7
    cmp iter, 15
    jle COL_8_15

    ; if it didnt jump, iter is 16
    mov ax, 0ADBh
    jmp WRITE_VRAM

COL_1_3:
    mov ax, 012Eh
    jmp WRITE_VRAM
COL_4_7:
    mov ax, 042Ah
    jmp WRITE_VRAM
COL_8_15:
    mov ax, 0EDBh
    jmp WRITE_VRAM
    
EXIT:
    ; moving the command line to the bottom and exiting the program
    mov ah, 02h
    mov bh, 00h
    mov dh, 18h
    mov dl, 00h
    int 10h
    
    mov ah, 04Ch
    int 21h

END START

核心错误定位

1. 迭代次数计数逻辑错误

代码中初始iter=1,且在计算新的z值之前判断iter是否等于16,导致最多仅执行15次迭代,而非题目要求的16次。具体流程:

  • 初始iter=1,第一次循环计算z₁后iter变为2
  • 当iter=16时,直接跳转到DRAW_PIXEL,未执行第16次迭代计算
  • 未逃逸的点本应是完成16次迭代后仍未满足逃逸条件的,但当前逻辑提前终止,导致这部分点的颜色分类错误。

2. 定点数除法的精度损失(次要)

使用idiv进行有符号除法会丢弃余数,导致部分计算存在精度损失,例如x=65时x²=4225,4225/64=66.015625,idiv仅保留整数部分66,这会影响图形的细节精度,但不是导致整体图形不符的主要原因。

修复建议

调整迭代计数逻辑

将iter初始值改为0,并调整循环内的判断顺序,确保执行完整16次迭代:

COL_LOOP:
    ; initial values of x,y from z_0
    mov x, 0
    mov y, 0
    mov iter, 0  ; 初始迭代次数设为0(未执行任何迭代)

MANDEL_LOOP:
    ; calculating x^2/64
    mov ax, x
    imul x              ; DX:AX = x * x
    mov bx, 64
    idiv bx             ; AX = (DX:AX) / 64
    mov x_sqr, ax       

    ; calculating y^2/64
    mov ax, y
    imul y              ; DX:AX = y * y
    mov bx, 64
    idiv bx             ; AX = (DX:AX) / 64
    mov y_sqr, ax       

    ; escape condition
    mov bx, x_sqr
    add bx, y_sqr
    cmp bx, 256         
    jg DRAW_PIXEL       

    ; 检查是否已完成16次迭代,未完成则继续计算
    cmp iter, 16
    je DRAW_PIXEL       

    ; calc saving y_new = (xy) / 32 + c_y
    mov ax, x
    imul y              ; DX:AX = x * y
    mov bx, 32
    idiv bx             ; AX = (DX:AX) / 32
    add ax, c_y
    mov y, ax

    ; calc saving x_new = x_sqr - y_sqr + c_x
    mov ax, x_sqr
    sub ax, y_sqr
    add ax, c_x
    mov x, ax                   

    inc iter  ; 完成一次迭代,计数加1
    jmp MANDEL_LOOP

可选优化(精度提升)

若需减少精度损失,可将除法改为右移操作(平方必然非负,乘积的符号可通过算术右移正确处理):

; 替换x²/64的idiv为右移
mov ax, x
imul x              ; DX:AX = x*x(非负)
sar ax, 6           ; AX = (x*x) >>6 = x²/64
mov x_sqr, ax

; 替换y²/64的idiv为右移
mov ax, y
imul y              ; DX:AX = y*y(非负)
sar ax, 6           ; AX = (y*y) >>6 = y²/64
mov y_sqr, ax

; 替换xy/32的idiv为右移
mov ax, x
imul y              ; DX:AX = x*y
sar ax, 5           ; AX = (x*y) >>5 = xy/32
add ax, c_y
mov y, ax

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.02 04:08:10