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
- 1-3次逃逸:
用户提供的汇编代码
.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
相关产品推荐
相关产品推荐

