編制一個簡單日歷查詢工具,輸入年、月、日,能夠判斷當日的星期數,并進行輸出,數據的輸入和結果的輸出要有必要的提示,且提示獨占一行。
查閱資料
? 經過查閱資料,發現有兩個相關的算法可以解決這個問題:
-
蔡勒公式
W=[C/4]?2C+Y+[Y/4]+[13?(M+1)/5]+D?1W=[C/4]-2C+Y+[Y/4]+[13*(M+1)/5]+D-1 W=[C/4]?2C+Y+[Y/4]+[13?(M+1)/5]+D?1
公式中的符號含義如下:- 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:日
- [ ]代表取整,即只要整數部分。
-
基姆拉爾森計算公式
Week=(d+2?m+3?(m+1)/5+y+y/4?y/100+y/400+1)mod7Week = (d+2*m+3*(m+1)/5+y+y/4-y/100+y/400+1) mod 7 Week=(d+2?m+3?(m+1)/5+y+y/4?y/100+y/400+1)mod7
公式中的符號含義如下:- y : 年份(四位數)
- m: 月份(m大于等于3,小于等于14,某年的1、2月要看作上一年的13、14月來計算,比如2003年1月1日要看作2002年的13月1日來計算)
- d : 日期
- 當Week==0Week==0Week==0的時候為周日
設計構思
? 基姆拉爾森計算公式的輸入更加友好,因此我決定使用基姆拉爾森計算公式解決問題。
? 公式主要涉及加減乘除四則運算,輸入主要是年月日三個數字。輸出為星期數。
? 因此主要的工作有:
- 提示用戶輸入年月日,并進行錯誤檢查(檢查是否是數字,位數是否錯誤)
- 檢查月份是否在正確的范圍內(0~12)
- 檢查日期是否在正確的范圍內
- 是否小于1
- 是否大于該月的最大日期
- 是否是閏月,如果是閏月需要特別對待
- 使用基姆拉爾森計算公式計算星期數
- 輸出結果,并詢問是否再次輸入
流程圖
實現代碼
ASSUME cs:CODE, ds:DATA, ss:STACK DATA SEGMENTS_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 0month db 0day db 0Max_Day db 0,31,28,31,30,31,30,31,31,30,31,30,31tmp dw 0week1 db 'Monday$'week2 db 'Tuesday$'week3 db 'Wednesday$'week4 db 'Thursday$'week5 db 'Friday$'week6 db 'Saturday$'week7 db 'Sunday$'hint db ' is $'DATA ENDSSTACK SEGMENTdb 256 dup(0)
STACK ENDSCODE SEGMENTNEXTLINE PROC NEAR ;輸出換行mov ah, 02Hmov dl, 0DHint 21Hmov dl, 0AHint 21Hret
NEXTLINE ENDPMAIN PROC
START:mov ax,DATAmov ds,ax ;初始化
INPUTYEAR:call NEXTLINElea dx, YearIn ;提示輸入yearmov ah, 09Hint 21Hlea dx, S_Year ;讀入yearmov ah, 0AHint 21Hcall NEXTLINE ;換行;檢查Year是否合法mov cl, S_Year+1 ;將實際長度保存到cx中mov ch, 0cmp cx, 4 ;檢查長度,同時計算year的值jnz WRONGYEARmov year, 0mov si, 2
CHECKYEAR:;判斷是否是數字mov dl, S_Year[si]cmp dl, '0'jl WRONGYEARcmp dl, '9'jg WRONGYEAR;是數字,計算yearmov ax, yearmov bx, 10mul bxmov dl, S_Year[si]sub dl, '0'mov dh, 0add ax, dxmov year, axinc siloop CHECKYEAR;year計算完畢jp INPUTMONTHWRONGYEAR:lea dx, WrongInfo ;輸出錯誤信息mov ah, 09Hint 21Hcall NEXTLINE ;換行jp INPUTYEAR ;重新輸入INPUTMONTH:lea dx, MonthIn ;提示輸入monthmov ah, 09Hint 21Hlea dx, S_Month ;讀入monthmov ah, 0AHint 21Hcall NEXTLINE ;換行;檢查Month是否合法mov cl, S_Month+1 ;將實際長度保存到cx中mov ch, 0cmp cx, 2 ;檢查長度,同時計算month的值jnz WRONGMONTHmov month, 0mov si, 2
CHECKMONTH:;判斷是否是數字mov dl, S_Month[si]cmp dl, '0'jl WRONGMONTHcmp dl, '9'jg WRONGMONTH;是數字,計算monthmov al, monthmov bl, 10mul blsub dl, '0'add al, dlmov month, alinc siloop CHECKMONTH;month計算完畢;判斷month是否在合法范圍內mov dl, monthcmp dl, 1jl WRONGMONTHcmp dl, 12jg WRONGMONTHjmp INPUTDAYWRONGMONTH:lea dx, WrongInfo ;輸出錯誤信息mov ah, 09Hint 21Hcall NEXTLINE ;換行jmp INPUTMONTH ;重新輸入INPUTDAY:lea dx, DayIn ;提示輸入daymov ah, 09Hint 21Hlea dx, S_Day ;讀入daymov ah, 0AHint 21Hcall NEXTLINE ;換行;檢查day是否合法mov cl, S_Day+1 ;將實際長度保存到cx中mov ch, 0cmp cx, 2 ;檢查長度,同時計算day的值jnz WRONGDAY_TMPmov si, 2mov day, 0
CHECKDAY:;判斷是否是數字mov dl, S_Day[si]cmp dl, '0'jl WRONGDAY_TMPcmp dl, '9'jg WRONGDAY_TMP;是數字,計算daymov al, daymov bl, 10mul blsub dl, '0'add al, dlmov day, alinc siloop CHECKDAY;day計算完畢;檢查day是否在合法范圍內mov dl, daycmp dl, 1jl WRONGDAYmov cl, monthmov ch, 0mov si, cxcmp dl, Max_Day[si] ;檢查有沒有該月份最大的一天jg CHECKLEAP ;檢查是不是閏月jmp INPUTEND ;輸入結束WRONGDAY_TMP:jmp WRONGDAYCHECKLEAP:mov dh, monthcmp dh, 2jne WRONGDAY ;如果不是2月就肯定不對;判斷是不是閏年if(year%4==0 && year%100!=0 || year%400==0) 是閏年mov ax, yearmov dx, 0mov bx, 400div bxcmp dx, 0je ISLEAP ;可以被400整除說明是閏月mov ax, yearmov dx, 0mov bx, 4div bxcmp dx, 0jne ISNOTLEAP ;不能被4整除說明不是閏月mov ax, yearmov dx, 0mov bx, 100div bxcmp dx, 0je ISNOTLEAP ;能被100整除說明不是閏月
ISLEAP:mov dl, daycmp dl, 29 jg WRONGDAY ;比29還大jmp INPUTEND ;輸入結束ISNOTLEAP:
WRONGDAY:lea dx, WrongInfo ;輸出錯誤信息mov ah, 09Hint 21Hcall NEXTLINE ;換行jmp INPUTDAY ;重新輸入INPUTEND: ;輸入合法,開始使用基姆拉爾森公式計算答案mov dl, monthcmp dl, 1je ADDMONTHcmp dl, 2je ADDMONTHjmp CALCULATEADDMONTH:mov al, monthadd al, 12mov month, almov ax, yearsub ax, 1mov year, axCALCULATE:mov bl, daymov bh, 0 ;bx := dayadd bl, monthadd bl, month ;bx += 2*monthmov al, monthadd al, 1mov ah, aladd al, ah add al, ah ;al := 3*(month+1)mov ah, 0mov cl, 5div clmov ah, 0 ;ax := al/5add bx, ax ;bx += axadd bx, year ;bx += yearmov ax, yearmov dx, 0mov cx, 4div cxadd bx, ax ;bx += year/4mov ax, yearmov dx, 0mov cx, 100div cxsub bx, ax ;bx -= year/100mov ax, yearmov dx, 0mov cx, 400div cxadd bx, ax ;bx += year/400add bx, 1 ;bx += 1mov ax, bxmov dx, 0mov cx, 7div cx ;bx %= 7mov bx, dx;基姆拉爾森公式計算完畢OUTPUT:call NEXTLINEmov al, S_Year+1add al, 2mov ah, 0mov si, ax mov S_Year[si], '$' ;加上字符串終結符$lea dx, S_Year+2 ;輸出年份mov ah, 09Hint 21Hmov dl, '\'mov ah, 02Hint 21Hmov al, S_Month+1add al, 2mov ah, 0mov si, ax mov S_Month[si], '$'lea dx, S_Month+2mov ah, 09Hint 21Hmov dl, '\'mov ah, 02Hint 21Hmov al, S_Day+1add al, 2mov ah, 0mov si, ax mov S_Day[si], '$'lea dx, S_Day+2mov ah, 09Hint 21Hlea dx, hintmov ah, 09Hint 21Hmov al, blcmp al, 0jnz D1lea dx, week7mov ah, 09Hint 21Hjmp D7INPUTYEAR_TMP1:call NEXTLINEjmp INPUTYEARD1: cmp al, 1jnz D2lea dx, week1mov ah, 09Hint 21Hjmp D7
D2:cmp al, 2jnz D3lea dx, week2mov ah, 09Hint 21Hjmp D7
D3:cmp al, 3jnz D4lea dx, week3mov ah, 09Hint 21Hjmp D7
D4:cmp al, 4jnz D5lea dx, week4mov ah, 09Hint 21Hjmp D7
D5:cmp al, 5jnz D6lea dx, week5mov ah, 09Hint 21Hjmp D7
D6:cmp al, 6jnz D7lea dx, week6mov ah, 09Hint 21H
D7:call NEXTLINEcall NEXTLINElea dx, ReaptInfo ;輸出重復查詢信息mov ah, 09Hint 21Hmov ah, 01H ;輸入字符int 21Hcmp al, 'Y'jz INPUTYEAR_TMP1 ;跳轉到中繼點1cmp al, 'y'jz INPUTYEAR_TMP1 ;跳轉到中繼點1mov ax, 4C00H ;程序結束int 21H
MAIN ENDPCODE ENDS
END START
運行結果
我將自己運行結果的視頻上傳在CSDN上啦:傳送門