汇编:实现日历星期数查询工具

编制一个简单日历查询工具,输入年、月、日,能够判断当日的星期数,并进行输出,数据的输入和结果的输出要有必要的提示,且提示独占一行。

查阅资料

​ 经过查阅资料,发现有两个相关的算法可以解决这个问题:

  1. 蔡勒公式
    W = [ C / 4 ] − 2 C + Y + [ Y / 4 ] + [ 13 ∗ ( M + 1 ) / 5 ] + D − 1 W=[C/4]-2C+Y+[Y/4]+[13*(M+1)/5]+D-1 W=[C/4]2C+Y+[Y/4]+[13(M+1)/5]+D1
    公式中的符号含义如下:

    • W:星期; W对7取模得:0-星期日,1-星期一,2-星期二,3-星期三,4-星期四,5-星期五,6-星期六,需要注意的是对负数的处理
    • C:世纪-1(前两位数)
    • Y:年(后两位数)
    • M:月(M大于等于3,小于等于14,即在蔡勒公式中,某年的1、2月要看作上一年的13、14月来计算,比如2003年1月1日要看作2002年的13月1日来计算
    • D:日
    • [ ]代表取整,即只要整数部分。
  2. 基姆拉尔森计算公式
    W e e k = ( d + 2 ∗ m + 3 ∗ ( m + 1 ) / 5 + y + y / 4 − y / 100 + y / 400 + 1 ) m o d 7 Week = (d+2*m+3*(m+1)/5+y+y/4-y/100+y/400+1) mod 7 Week=(d+2m+3(m+1)/5+y+y/4y/100+y/400+1)mod7
    公式中的符号含义如下:

    • y : 年份(四位数)
    • m: 月份(m大于等于3,小于等于14,某年的1、2月要看作上一年的13、14月来计算,比如2003年1月1日要看作2002年的13月1日来计算
    • d : 日期
    • W e e k = = 0 Week==0 Week==0的时候为周日

设计构思

基姆拉尔森计算公式的输入更加友好,因此我决定使用基姆拉尔森计算公式解决问题。

​ 公式主要涉及加减乘除四则运算,输入主要是年月日三个数字。输出为星期数。

​ 因此主要的工作有:

  • 提示用户输入年月日,并进行错误检查(检查是否是数字,位数是否错误)
  • 检查月份是否在正确的范围内(0~12)
  • 检查日期是否在正确的范围内
    • 是否小于1
    • 是否大于该月的最大日期
    • 是否是闰月,如果是闰月需要特别对待
  • 使用基姆拉尔森计算公式计算星期数
  • 输出结果,并询问是否再次输入

流程图

在这里插入图片描述


实现代码
ASSUME cs:CODE, ds:DATA, ss:STACK 

DATA SEGMENT
	S_Year 	db 	5,0,5 dup(0)
	S_Month db	3,0,3 dup(0)
	S_Day 	db	3,0,3 dup(0)
	YearIn	db	'please input year(eg:2020):$'
	MonthIn	db	'please	input month(eg:05):$'
	DayIn	db	'please input day(eg:01):$'
	WrongInfo db 'your input is illegal,please input again!$'
	ReaptInfo db 'Would you like to check again?(Y/n)	$'
	year 	dw	0
	month 	db	0
	day 	db	0
	Max_Day db	0,31,28,31,30,31,30,31,31,30,31,30,31
	tmp		dw	0
	week1	db	'Monday$'
	week2	db	'Tuesday$'
	week3	db	'Wednesday$'
	week4	db	'Thursday$'
	week5	db	'Friday$'
	week6	db	'Saturday$'
	week7	db	'Sunday$'
	hint	db	' is $'

DATA ENDS

STACK SEGMENT
	db 256	dup(0)
STACK ENDS

CODE SEGMENT

NEXTLINE PROC NEAR	;输出换行
	mov ah, 02H
	mov	dl, 0DH
	int 21H
	mov dl, 0AH
	int 21H
	ret
NEXTLINE ENDP

MAIN PROC
START:
	mov ax,DATA
	mov ds,ax	;初始化
INPUTYEAR:
	call NEXTLINE
	lea dx, YearIn	;提示输入year
	mov ah, 09H
	int 21H
	lea dx, S_Year 	;读入year
	mov ah, 0AH
	int 21H

	call NEXTLINE	;换行
	;检查Year是否合法
	mov cl, S_Year+1	;将实际长度保存到cx中
	mov ch, 0
	cmp cx, 4		;检查长度,同时计算year的值
	jnz WRONGYEAR
	mov year, 0
	mov si, 2
CHECKYEAR:
	;判断是否是数字
	mov dl, S_Year[si]
	cmp dl, '0'
	jl	WRONGYEAR
	cmp dl, '9'
	jg	WRONGYEAR
	;是数字,计算year
	mov ax, year
	mov bx, 10
	mul bx
	mov dl, S_Year[si]
	sub dl, '0'
	mov dh, 0
	add ax, dx
	mov year, ax
	inc si
	loop CHECKYEAR
	;year计算完毕
	jp	INPUTMONTH

WRONGYEAR:
	lea dx, WrongInfo	;输出错误信息
	mov ah, 09H
	int 21H
	call NEXTLINE		;换行
	jp	INPUTYEAR		;重新输入

INPUTMONTH:
	lea dx, MonthIn		;提示输入month
	mov ah, 09H
	int 21H
	lea dx, S_Month 	;读入month
	mov ah, 0AH
	int 21H

	call NEXTLINE		;换行
	;检查Month是否合法
	mov cl, S_Month+1	;将实际长度保存到cx中
	mov ch, 0
	cmp cx, 2			;检查长度,同时计算month的值
	jnz WRONGMONTH
	mov month, 0
	mov si, 2
CHECKMONTH:
	;判断是否是数字
	mov dl, S_Month[si]
	cmp dl, '0'
	jl	WRONGMONTH
	cmp dl, '9'
	jg	WRONGMONTH
	;是数字,计算month
	mov al, month
	mov bl, 10
	mul bl
	sub dl, '0'
	add al, dl
	mov month, al
	inc si
	loop CHECKMONTH
	;month计算完毕
	;判断month是否在合法范围内
	mov dl, month
	cmp dl, 1
	jl	WRONGMONTH
	cmp dl, 12
	jg	WRONGMONTH
	jmp INPUTDAY

WRONGMONTH:
	lea dx, WrongInfo	;输出错误信息
	mov ah, 09H
	int 21H
	call NEXTLINE		;换行
	jmp	INPUTMONTH		;重新输入

INPUTDAY:
	lea dx, DayIn	;提示输入day
	mov ah, 09H
	int 21H
	lea dx, S_Day 	;读入day
	mov ah, 0AH
	int 21H

	call NEXTLINE	;换行
	;检查day是否合法
	mov cl, S_Day+1	;将实际长度保存到cx中
	mov ch, 0
	cmp cx, 2		;检查长度,同时计算day的值
	jnz WRONGDAY_TMP
	mov si, 2
	mov day, 0
CHECKDAY:
	
	;判断是否是数字
	mov dl, S_Day[si]
	cmp dl, '0'
	jl	WRONGDAY_TMP
	cmp dl, '9'
	jg	WRONGDAY_TMP
	;是数字,计算day
	mov al, day
	mov bl, 10
	mul bl
	sub dl, '0'
	add al, dl
	mov day, al
	inc si
	loop CHECKDAY
	;day计算完毕
	;检查day是否在合法范围内

	mov dl, day
	cmp dl, 1
	jl	WRONGDAY
	mov cl, month
	mov ch, 0
	mov si, cx
	cmp dl, Max_Day[si]	;检查有没有该月份最大的一天
	jg	CHECKLEAP		;检查是不是闰月

	jmp	INPUTEND		;输入结束

WRONGDAY_TMP:
	jmp WRONGDAY

CHECKLEAP:
	mov dh, month
	cmp dh, 2
	jne WRONGDAY		;如果不是2月就肯定不对
	;判断是不是闰年if(year%4==0 && year%100!=0 || year%400==0) 是闰年
	mov ax, year
	mov dx, 0
	mov bx, 400
	div bx
	cmp dx, 0
	je	ISLEAP 			;可以被400整除说明是闰月
	mov ax, year
	mov dx, 0
	mov bx, 4
	div bx
	cmp dx, 0
	jne ISNOTLEAP		;不能被4整除说明不是闰月
	mov ax, year
	mov dx, 0
	mov bx, 100
	div bx
	cmp dx, 0
	je 	ISNOTLEAP		;能被100整除说明不是闰月
ISLEAP:
	mov dl, day
	cmp dl, 29			
	jg	WRONGDAY		;比29还大
	jmp	INPUTEND		;输入结束

ISNOTLEAP:
WRONGDAY:
	lea dx, WrongInfo	;输出错误信息
	mov ah, 09H
	int 21H
	call NEXTLINE		;换行
	jmp	INPUTDAY		;重新输入

INPUTEND:				;输入合法,开始使用基姆拉尔森公式计算答案
	mov dl, month
	cmp dl, 1
	je	ADDMONTH
	cmp	dl, 2
	je 	ADDMONTH
	jmp CALCULATE

ADDMONTH:
	mov al, month
	add al, 12
	mov month, al
	mov ax, year
	sub ax, 1
	mov year, ax

CALCULATE:

	mov bl, day
	mov bh, 0			;bx := day
	add bl, month
	add bl, month 		;bx += 2*month

	mov al, month
	add al, 1
	mov ah, al
	add al, ah 
	add al, ah 			;al := 3*(month+1)

	mov ah, 0
	mov cl, 5
	div cl
	mov ah, 0			;ax := al/5
	add bx, ax			;bx += ax

	add bx, year 		;bx += year
	mov ax, year
	mov dx, 0
	mov cx, 4
	div cx
	add bx, ax			;bx += year/4
	mov ax, year
	mov dx, 0
	mov cx, 100
	div cx
	sub bx, ax			;bx -= year/100
	mov ax, year
	mov dx, 0
	mov cx, 400
	div cx
	add bx, ax			;bx += year/400

	add bx, 1			;bx += 1
	mov ax, bx
	mov dx, 0
	mov cx, 7
	div cx				;bx %= 7
	mov bx, dx

	;基姆拉尔森公式计算完毕

OUTPUT:
	call NEXTLINE
	mov al, S_Year+1
	add al, 2
	mov ah, 0
	mov si, ax	
	mov S_Year[si], '$'	;加上字符串终结符$
	lea dx, S_Year+2	;输出年份
	mov ah, 09H
	int 21H

	mov dl, '\'
	mov ah, 02H
	int 21H

	mov al, S_Month+1
	add al, 2
	mov ah, 0
	mov si, ax	
	mov S_Month[si], '$'
	lea dx, S_Month+2
	mov ah, 09H
	int 21H

	mov dl, '\'
	mov ah, 02H
	int 21H

	mov al, S_Day+1
	add al, 2
	mov ah, 0
	mov si, ax	
	mov S_Day[si], '$'
	lea dx, S_Day+2
	mov ah, 09H
	int 21H

	lea	dx,	hint
	mov ah,	09H
	int 21H

	mov al, bl
	cmp al, 0
	jnz D1
	lea dx, week7
	mov ah, 09H
	int 21H
	jmp	D7

INPUTYEAR_TMP1:
	call NEXTLINE
	jmp INPUTYEAR

D1:	
	cmp al, 1
	jnz D2
	lea dx, week1
	mov ah, 09H
	int 21H
	jmp	 D7
D2:
	cmp al, 2
	jnz D3
	lea dx, week2
	mov ah, 09H
	int 21H
	jmp	D7 
D3:
	cmp al, 3
	jnz D4
	lea dx, week3
	mov ah, 09H
	int 21H
	jmp	D7 
D4:
	cmp al, 4
	jnz D5
	lea dx, week4
	mov ah, 09H
	int 21H
	jmp	D7 
D5:
	cmp al, 5
	jnz D6
	lea dx, week5
	mov ah, 09H
	int 21H
	jmp	D7 
D6:
	cmp al, 6
	jnz D7
	lea dx, week6
	mov ah, 09H
	int 21H
D7:
	call NEXTLINE
	call NEXTLINE

	lea dx, ReaptInfo	;输出重复查询信息
	mov ah, 09H
	int 21H

	mov ah, 01H			;输入字符
	int 21H

	cmp al, 'Y'
	jz INPUTYEAR_TMP1	;跳转到中继点1
	cmp al, 'y'
	jz INPUTYEAR_TMP1 	;跳转到中继点1

	mov ax, 4C00H		;程序结束
	int 21H
MAIN ENDP

CODE ENDS
END START
	



运行结果

我将自己运行结果的视频上传在CSDN上啦:传送门

  • 1
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值