目录
写在前面
编译器为 MASM-v6.11
写的一坨屎。
斐波那契数列前 50 项
最多支持输出 30 位十进制数。
.model large
assume cs:code, ss:stack
position segment; 在屏幕上的输出位置
dw 00a0h
position ends
string segment ;将数组转化为字符串输出
db 30 dup (0), 0
string ends
data segment ;三个用于递推 fib 的数组
a1 db 1, 29 dup (0)
a2 db 1, 29 dup (0)
a3 db 1, 29 dup (0)
data ends
stack segment ;栈
dw 40H dup(0)
stack ends
code segment
main:
call init ;初始化栈
call transforming ;首先输出前两项
call show_string
call transforming
call show_string
mov cx, 50 - 2 ;输出之后的 48 项(理论上可以正确输出无限项,仅需调整程序开头的内存空间与程序中的迭代边界即可。
main_s1:
call get_fib ;计算下一项 fib 并存入 a3
call move_fib ;将 a2 移动到 a1,a3 移动到 a2
call transforming ;将 a3 转化为字符串并存入 string
call show_string ;输出字符串到显存
loop main_s1
mov ax, 4c00h
int 21h
init: ;初始化栈
mov ax, stack
mov ss, ax
mov sp, 40H
ret
get_fib: ;计算下一项 fib 并存入 a3
push dx
push si
push ax
push bx
push cx
push ds
mov ax, data
mov ds, ax
mov cx, 30
mov si, 0
mov ax, 0
get_fib_s:
add al, ds:[si] ;利用上一次计算的商(进位)与该位相加
mov bl, ds:[si + 30]
add al, bl
mov bl, 10 ;计算这一位整除 10
div bl
mov ds:[si + 60], ah ;将余数存入该位
mov ah, 0 ;清空余数
inc si ;将商用于下一次计算
loop get_fib_s
pop ds
pop cx
pop bx
pop ax
pop si
pop dx
ret
move_fib: ;将 a2 移动到 a1,a3 移动到 a2
push dx
push si
push ax
push bx
push cx
push ds
mov ax, data
mov ds, ax
mov cx, 30
mov si, 0
move_fib_s1: ;将 a2 移动到 a1
mov al, ds:[si + 30]
mov ds:[si], al
inc si
loop move_fib_s1
mov cx, 30
mov si, 0
move_fib_s2: ;将 a3 移动到 a2
mov al, ds:[si + 60]
mov ds:[si + 30], al
inc si
loop move_fib_s2
pop ds
pop cx
pop bx
pop ax
pop si
pop dx
ret
transforming: ;将 a3 转化为字符串并存入 string
push cx
push dx
push si
push ax
push bx
push ds
push es
mov ax, data
mov ds, ax
mov ax, string
mov es, ax
mov cx, 30
mov si, 0
transforming_s1: ;将 a3 转化为字符串并存入 string
mov al, ds:[si + 30]
add al, '0' ;数字加 '0' 变为数字字符
mov es:[si], al
inc si
loop transforming_s1
mov cx, 15
mov si, 0
mov bx, 29
transforming_s2: ;将 stirng 中的内容反向以便于输出
mov al, es:[si]
mov dl, es:[bx] ;交换首尾元素
mov es:[bx], al
mov es:[si], dl
inc si
sub bx, 1
loop transforming_s2
pop es
pop ds
pop bx
pop ax
pop si
pop dx
pop cx
ret
show_string: ;输出字符串到显存
push cx
push dx
push si
push ax
push bx
push ds
push es
mov ax, position ;当前输出的位置
mov ds, ax
mov bx, ds:[0]
mov cl, 000fh ;color
mov ax, string
mov ds, ax
mov si, 0
mov ax, 0b800h
mov es, ax
mov al, cl
mov ch, 0
mov si, 0
mov ah, 0
show_string_s:
mov cl, ds:[si]
jcxz show_string_ok
sub cl, '0'
add cl, ah
jcxz show_string_is_0 ;忽略前导零
sub cl, ah
mov ah, 1
add cl, '0'
mov es:[bx], cl ;输出该位
inc bx
mov es:[bx], al
inc bx
show_string_is_0:
inc si
jmp short show_string_s
show_string_ok:
mov cl, ' ' ;输出空格
mov es:[bx], cl
inc bx
mov es:[bx], al
inc bx
mov ax, position ;将当前输出位置存入内存
mov ds, ax
mov ds:[0], bx
mov cx, 30
mov ax, string
mov ds, ax
mov si, 0
show_string_s2: ;清空字符串
mov ds:[si], 0
inc si
loop show_string_s2
pop es
pop ds
pop bx
pop ax
pop si
pop dx
pop cx
ret
code ends
end
求 1e8 内的质数
出这么几把提老师是恼弹?
地球人都知道的的性质是合数 \(x\) 至少有一个小于 \(\sqrt x\) 的因子,于是试除时仅需枚举到 \(\sqrt x\) 级别即可。
原理是压位高精,把两个 16 位当 32 位用,并且手动处理进位和借位。求余运算则用多次减法替代。
复杂度上界 \(O(n\sqrt n)\) 再乘上减法模拟求余的超大常熟,跑的超级慢。
加了点优化,从 3 开始枚举并每次加 2,枚举因子试除时从小到大枚举,能快一点是一点呃呃。
这逼东西怎么检查啊、、、
assume cs:code, ss:stack
zero segment
db 0
zero ends
value segment ;存当前要检查是否为质数的值
dw 3, 0
value ends
stack segment ;栈
dw 40H dup(0)
stack ends
code segment
main:
call init ;初始化栈
mov dl, '2' ;先输出 2 和空格
mov ah, 2
int 21h
mov dl, ' '
mov ah, 2
int 21h
mov cx, 1000 ;二重循环来枚举 3~1e7 的值
main_s1:
push cx
mov cx, 10000
main_s2:
call check ;检查当前枚举到的 value 是否为质数
push cx
mov cx, ax
jcxz main_s3
call show
main_s3:
pop cx
call get_next ;value += 2
call get_next
sub cx, 1
loop main_s2
pop cx
loop main_s1
mov ax, 4c00h
int 21h
init: ;初始化栈
mov ax, stack
mov ss, ax
mov sp, 40H
ret
get_next: ;计算下一项
push dx
push si
push ax
push bx
push cx
push es
push ds
mov ax, value
mov es, ax
mov ax, es:[0] ;ax 为低位
mov bx, es:[2] ;bx 为高位
add ax, 1
cmp ax, 10000
jb get_next_done
mov ax, 0 ;低位超过 10000 则进位
add bx, 1
get_next_done:
mov es:[0], ax
mov es:[2], bx
pop ds
pop es
pop cx
pop bx
pop ax
pop si
pop dx
ret
check:
; mov ax, 1
; ret
push cx
push dx
push si
push bx
push es
mov ax, value
mov es, ax
mov ax, es:[0]
mov bx, es:[2]
mov dx, 2
mov cx, 9999 ;确定试除的上界
cmp bx, 1
jae check_s1
cmp ax, 3
jbe check_is_prime
mov cx, ax
sub cx, 1
check_s1:
mov ax, value
mov es, ax
mov ax, es:[0]
mov bx, es:[2]
check_s2: ;使用当前 cx 的值对 value 进行试除,减法模拟求余运算
cmp ax, dx
ja check_minus
jb check_s3
cmp bx, 0
je check_is_not_prime ;恰好整除则非质数
check_s3:
cmp bx, 1 ;向高位借位,借不到则无法整除,检查下一个 cx
jb check_s4
sub bx, 1
add ax, 10000
check_minus:
sub ax, dx ;做减法模拟求余运算
jmp check_s2
check_s4:
sub cx, 1
inc dx
cmp cx, 1
ja check_s1
check_is_prime:
mov ax, 1
jmp check_done
check_is_not_prime:
mov ax, 0
check_done:
pop es
pop bx
pop si
pop dx
pop cx
ret
show: ;输出字符串
push cx
push dx
push si
push ax
push bx
push es
mov ax, zero
mov ds, ax
mov ds:[0], 0
mov ax, value
mov es, ax
mov bx, es:[2] ;先输出高位
mov cx, 1000
call dout
mov cx, 100
call dout
mov cx, 10
call dout
mov cx, 1
call dout
mov bx, es:[0] ;再输出低位
mov cx, 10000
call dout
mov cx, 1000
call dout
mov cx, 100
call dout
mov cx, 10
call dout
mov cx, 1
call dout
mov dl, ' '
mov ah, 2
int 21h ;输出一个空格
pop es
pop bx
pop ax
pop si
pop dx
pop cx
ret
dout:
push dx
push si
push ax
push es
mov dx,0 ;dx清0,除cx时,被除数为dx,ax
mov ax,bx ;将bx值(第一次为输入的数,随后为余数)赋值给ax
div cx ;(dx,ax),实际为ax(dx==0)除以cx(cx值在调用程序前设置,作为参数传递进来)
xchg ax,dx ;ax与dx交换内容。交换后:ax中为余数,dx中为商
mov bx,ax ;将ax值(余数)赋予bx(进入下一轮运算)
;如果用户前面输入65535,那么在第一轮除以10000后,dx中值为6,bx中值为5535
cmp dl,0
jne outanum ;如果dx中值不为0,则直接输出相应的数值
mov ax, zero
mov ds, ax
cmp ds:[0], 0 ;如果dx中值为0,那么判断是前面无意义的0,还是中间有意义的0。
;如305,那么如果不进行次判断将输入00305。通过此位可以不输出前面两个0,但是输出中间0。
je con ;如果是前面无意义的0 ,则不输出
outanum:
mov ds:[0], 1 ;如果输出了一个大于0的数字,则置标志位为1,使得其后所有0都会被输出
add dl, 30h ;dl中数值加上30h,变成对应的ASCII码。
mov ah, 2
int 21h ;输出该数字
con:
pop es
pop ax
pop si
pop dx
ret
code ends
end
冒泡排序
十个数。
stack segment ;栈
dw 40H dup(0)
stack ends
d1 segment
a dw 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
crlf db 0dh,0ah,'$'
d1 ends
data segment
zero db 0
data ends
code segment
main proc far
assume cs:code, ds:d1, ss:stack
mov sp, 40H
start:
push ds
sub ax,ax
push ax
mov ax,d1
mov ds,ax
mov cx,10
mov si,0
lop0:
push cx
mov bx,a[si]
call decout ;输出一个数值
assume cs:code,ds:d1
mov dl,' '
mov ah,2
int 21h ;输出一个空格
add si,2
pop cx
loop lop0
lea dx,crlf
mov ah,9
int 21h
mov cx,9
lop1:
push cx
mov bx,0
lop2:
mov ax,a[bx]
cmp ax,a[bx+2]
jbe con
xchg ax,a[bx+2]
mov a[bx],ax
con:
add bx,2
loop lop2
pop cx
loop lop1
mov cx,10
mov si,0
lop4:
push cx
mov bx,a[si]
call decout
assume cs:code,ds:d1
mov dl,' '
mov ah,2
int 21h
add si,2
pop cx
loop lop4
ret
main endp
decout proc far
assume cs:code,ds:data
push ds
mov ax,data
mov ds,ax
cmp bx,0
jne next
mov dl,'0'
mov ah,2
int 21h
jmp return
next:
mov zero,0
mov cx,10000
call dout
mov cx,1000
call dout
mov cx,100
call dout
mov cx,10
call dout
mov cx,1
call dout
return:
pop ds
ret
decout endp
dout proc near
mov dx,0
mov ax,bx
div cx
xchg ax,dx
mov bx,ax
cmp dl,0
jne outanum
cmp zero,0
je decout_con
outanum:
mov zero,1
add dl,30h
mov ah,2
int 21h
decout_con:
ret
dout endp
code ends
end
写在最后
写的一坨屎。
标签:汇编,8086,课到,mov,pop,cx,push,ax,bx From: https://www.cnblogs.com/rainycolor/p/17824858.html