02/02/2020是一个回文日,因为读取从左到右或从右到左的日期仍指相同的日历日期。而且因为使用DD/MM/YYYY格式或MM.DD.YYYY格式并不重要,所以它被称为“通用回文日”。
没有一年可以有超过一个回文日。这一点很重要,因为我们只需考虑年份,就可以通过排序获得一个按时间顺序排列的列表。
在10000年间,我们可以用4个小数位来表示,准确地说有366个回文日。
366 is (31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31)日期和月份的每一个组合都会产生一个有效的日期。自2092年(29/02/ 2092 )和9220 (02.29.9220)都将确实是闰年以来,没有必要特别注意2月29日。希望我们还在..。
日和月的组合使用嵌套循环完成。外部循环必须在一个月内迭代,因为我们只有在选择了一个月并查询了一个查找表(LUT),才能知道内环的迭代计数,以确定该月份有多少天。
仅仅结合并不能产生按时间顺序所寻求的结果。通常,我们会从组合操作中对the输出进行排序,但我发现将the输入排序到组合部分可能要快得多。甚至比产生一个未排序的列表还要快!此外,如果对输出排序在很大程度上取决于所选排序方法的质量,则对输入进行排序不会(很大)。我的代码从来不需要排序超过31个值。
如果我能使用更多的查找表,我就可以很容易地选择不排序。查找表的问题在于知道什么时候足够了。极端是一个大的查找表,最后的结果准备就绪。它的乐趣在哪里?这并不是说我还没有研究过:用4个嵌入式查找表的214个字节替换PALINDR1.ASM_Part1中的70个代码字节将使执行时间从5.4秒缩短到3.0秒。
5.4 µsec PALINDR1.ASM Sorted inputs
6.9 µsec PALINDR2.ASM Unsorted
111.8 µsec PALINDR3.ASM Sorted outputs当然,这些时间不包括int 21h DOS.PrintString调用。
; PALINDR1.ASM (c) 2020 Sep Roland
; --------------------------------
; assemble with FASM
ORG 256
; This program lists all palindrome days according to DD/MM/YYYY
; It sorts the inputs to obtain a chronological list
; Part 1 fills 4 ordered tables with the reversed textual representations
; of months and days
push 31 30 29 12 ; (1)
mov bp, 1010'1101'0101b ; LUT DaysPerMonth (1 is 31, 0 is less)
mov di, T12
mov bx, 1
NextT: pop dx ; (1) -> DX={12,29,30,31}
push di ; (2) DI points behind a sentinel zero
lea cx, [bx-1]
rep movsw ; Copy the mother table
mov cl, 10 ; CONST
.Next: mov ax, bx
div cl
add ax, 3030h
shr bp, 1 ; Hiding the DaysPerMonth info
rcl ax, 1 ; ... in bit 0
add di, 2
push di ; (3)
.Sort: mov [di], si ; Garbage the 1st time
sub di, 2
mov si, [di-2] ; This could read the sentinel
cmp si, ax
jg .Sort
mov [di], ax
pop di ; (3)
inc bx
cmp bx, dx
jbe .Next
xor ax, ax ; Zero terminator on each table is at
stosw ; the same time sentinel of next table
pop si ; (2) New table is mother of next table
cmp dx, 31
jb NextT
; Part 2 makes all the valid month and day combinations (366 in all)
mov si, T12
lodsw
shr ax, 1 ; -> CF (*) Extract DaysPerMonth info
; The outer loop updates the month and century fields
Outer: push si ; (4)
mov si, T12+(12+1+29+1+30+1)*2 ; Point at T31
jc .a ; (*) OK, 31 days
sub si, (30+1)*2 ; Point at T30
cmp ax, "02" ; Is it February ?
jne .a ; No, 30 days
sub si, (29+1)*2 ; Point at T29, 29 days
.a: mov [String+3], ax ; 2-digit month
mov [String+6], ah ; 2-digit century
mov [String+7], al
lodsw
shr ax, 1
; The inner loop updates the day and year fields
Inner: mov [String+0], ax ; 2-digit day
mov [String+8], ah ; 2-digit year
mov [String+9], al
mov dx, String
mov ah, 09h ; DOS.PrintString
int 21h
lodsw
shr ax, 1 ; No info to extract, but
jnz Inner ; ... used as iterator test
pop si ; (4)
lodsw
shr ax, 1 ; -> CF (*) Extract DaysPerMonth info
jnz Outer
mov ax, 4C00h ; DOS.Terminate
int 21h
; --------------------------------------
String: db '../../....', 13, 10, '作为比较,这里有未排序和后排序的DD/MM/YYYY版本:; PALINDR2.ASM (c) 2020 Sep Roland
; --------------------------------
; assemble with FASM
ORG 256
; This program lists all palindrome days according to DD/MM/YYYY
; It does not produce a chronological list
; The code makes all the valid month and day combinations (366 in all)
xor si, si ; Month
; The outer loop updates the month and century fields
Outer: mov cl, [MDays+si] ; LUT DaysPerMonth
inc si
mov ax, si
aam
add ax, "00"
mov [String+6], ax ; 2-digit century
mov [String+3], ah ; 2-digit month
mov [String+4], al
xor di, di ; Day
; The inner loop updates the day and year fields
Inner: inc di
mov ax, di
aam
add ax, "00"
mov [String+8], ax ; 2-digit year
mov [String+0], ah ; 2-digit day
mov [String+1], al
mov dx, String
mov ah, 09h ; DOS.PrintString
int 21h
dec cl ; Next day
jnz Inner
cmp si, 12 ; Next month
jb Outer
mov ax, 4C00h ; DOS.Terminate
int 21h
; --------------------------------------
String: db '../../....', 13, 10, '; PALINDR3.ASM (c) 2020 Sep Roland
; --------------------------------
; assemble with FASM
ORG 256
; This program lists all palindrome days according to DD/MM/YYYY
; It sorts the outputs to produce a chronological list
; Part 1 creates an ordered list of palindrome years
xor dx, dx ; Table size
xor si, si ; Month
; The outer loop inserts the reversed textual representation of the month
; as the most significant part of the 4-byte string in EBX
; e.g. for February - EBX=5048____h (EBX="__02")
Outer: mov cl, [MDays+si] ; LUT DaysPerMonth
inc si
mov ax, si
aam
add ax, "00"
xchg al, ah
mov bx, ax
shl ebx, 16
xor di, di ; Day
; The inner loop inserts the reversed textual representation of the day
; as the least significant part of the 4-byte string in EBX
; e.g. for 1 February - EBX=50484948h (EBX="0102")
Inner: inc di
mov ax, di
aam
add ax, "00"
xchg al, ah
mov bx, ax
; MergeSorting EBX into the growing table
; e.g. EBX=50484948h (EBX="0102") corresponds to the year 2010
mov bp, dx
Look: mov eax, [Table+bp-4] ; This could read the sentinel
cmp eax, ebx
jb Found
mov [Table+bp], eax
sub bp, 4
jnz Look
Found: mov [Table+bp], ebx ; Add new element
add dx, 4 ; The array grows
dec cl ; Next day
jnz Inner
cmp si, 12 ; Next month
jb Outer
; Part 2 displays the whole list of completed palindrome days
mov si, Table
mov di, String
mov dx, di
Show: lodsd
mov [di], ax ; 2-digit day
bswap eax
mov [di+3], ah ; \ 2-digit month
mov [di+4], al ; /
mov [di+6], eax ; 4-digit year
mov ah, 09h ; DOS.PrintString
int 21h
cmp si, Table+366*4
jb Show
mov ax, 4C00h ; DOS.Terminate
int 21h
; --------------------------------------
String: db '../../....', 13, 10, '关于MM.DD.YYYY格式的最后说明(未显示)引用一段话:日和月的组合使用嵌套循环完成。外部循环必须在一个月内迭代,因为我们只有在选择了一个月并查询了一个查找表(LUT),才能知道内环的迭代计数,以确定该月份有多少天。这个约束对于未排序和后排序的MM.DD.YYYY版本并不重要,但是对于预排序的MM.DD.YYYY版本,我看不到任何方法。有什么想法吗?
ALIGN 2
dw 0 ; Sentinel
T12: rw 12+1+29+1+30+1+31+1作为比较,这里有未排序和后排序的DD/MM/YYYY版本:A5A6K17关于MM.DD.YYYY格式的最后说明(未显示)K28引用一段话:J19日和月的组合使用嵌套循环完成。外部循环必须在一个月内迭代,因为我们只有在选择了一个月并查询了一个查找表(LUT),才能知道内环的迭代计数,以确定该月份有多少天。J210这个约束对于未排序和后排序的MM.DD.YYYY版本并不重要,但是对于预排序的MM.DD.YYYY版本,我看不到任何方法。有什么想法吗?
MDays: db 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31A6K17关于MM.DD.YYYY格式的最后说明(未显示)K28引用一段话:J19日和月的组合使用嵌套循环完成。外部循环必须在一个月内迭代,因为我们只有在选择了一个月并查询了一个查找表(LUT),才能知道内环的迭代计数,以确定该月份有多少天。J210这个约束对于未排序和后排序的MM.DD.YYYY版本并不重要,但是对于预排序的MM.DD.YYYY版本,我看不到任何方法。有什么想法吗?
ALIGN 2
dw 0 ; Sentinel
T12: rw 12+1+29+1+30+1+31+1作为比较,这里有未排序和后排序的DD/MM/YYYY版本:
A5A6K17关于MM.DD.YYYY格式的最后说明(未显示)K28
引用一段话:
J19
日和月的组合使用嵌套循环完成。外部循环必须在一个月内迭代,因为我们只有在选择了一个月并查询了一个查找表(LUT),才能知道内环的迭代计数,以确定该月份有多少天。
J210
这个约束对于未排序和后排序的MM.DD.YYYY版本并不重要,但是对于预排序的MM.DD.YYYY版本,我看不到任何方法。有什么想法吗?
MDays: db 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ALIGN 4 dd 0 ; Sentinel Table: rd 366K17关于MM.DD.YYYY格式的最后说明(未显示)K28
引用一段话:
J19
日和月的组合使用嵌套循环完成。外部循环必须在一个月内迭代,因为我们只有在选择了一个月并查询了一个查找表(LUT),才能知道内环的迭代计数,以确定该月份有多少天。
J210
这个约束对于未排序和后排序的MM.DD.YYYY版本并不重要,但是对于预排序的MM.DD.YYYY版本,我看不到任何方法。有什么想法吗?
ALIGN 2 dw 0 ; Sentinel T12: rw 12+1+29+1+30+1+31+1
作为比较,这里有未排序和后排序的DD/MM/YYYY版本:
A5A6K17关于MM.DD.YYYY格式的最后说明(未显示)K28
引用一段话:
J19
日和月的组合使用嵌套循环完成。外部循环必须在一个月内迭代,因为我们只有在选择了一个月并查询了一个查找表(LUT),才能知道内环的迭代计数,以确定该月份有多少天。
J210
这个约束对于未排序和后排序的MM.DD.YYYY版本并不重要,但是对于预排序的MM.DD.YYYY版本,我看不到任何方法。有什么想法吗?
MDays: db 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31A6K17关于MM.DD.YYYY格式的最后说明(未显示)K28
引用一段话:
J19
日和月的组合使用嵌套循环完成。外部循环必须在一个月内迭代,因为我们只有在选择了一个月并查询了一个查找表(LUT),才能知道内环的迭代计数,以确定该月份有多少天。
J210
这个约束对于未排序和后排序的MM.DD.YYYY版本并不重要,但是对于预排序的MM.DD.YYYY版本,我看不到任何方法。有什么想法吗?
ALIGN 2 dw 0 ; Sentinel T12: rw 12+1+29+1+30+1+31+1
作为比较,这里有未排序和后排序的DD/MM/YYYY版本:
A5A6K17关于MM.DD.YYYY格式的最后说明(未显示)K28
引用一段话:
J19
日和月的组合使用嵌套循环完成。外部循环必须在一个月内迭代,因为我们只有在选择了一个月并查询了一个查找表(LUT),才能知道内环的迭代计数,以确定该月份有多少天。
J210
这个约束对于未排序和后排序的MM.DD.YYYY版本并不重要,但是对于预排序的MM.DD.YYYY版本,我看不到任何方法。有什么想法吗?
发布于 2020-02-28 15:29:39
列出所有回文天数
代码生成所有有效的月和日组合(总计366)。它使用4个预先排序的查找表(嵌入速度)来获得一个时间顺序列表.
在MM.DD.YYYY格式中,YYYY一年中最重要的部分反映在DD日。这将用于外循环。外部循环在T31列表中运行,以便处理所有可能的天数。
在MM.DD.YYYY格式中,YYYY一年中最不重要的部分反映在月份MM.中。这将用于内循环。然而,迭代次数将因日值大于(a)、等于(b)或小于(c)而变化:
(A)当外循环处理第31天时,.The内环在T7列表中运行。存储为“31”。(B)当外循环处理第30天时,.The内环在T11列表中运行。存储为“30”。(C)外部循环处理的.The内环每隔一天运行一次T12列表。
T31列表是范围内数字的两个字符ASCII表示的有序列表。T12列表是集合{1,2,3,4,5,6,7,8,9,10,11,12}中两个字符ASCII表示的有序列表。有29+日的月份。(就这个项目而言,二月有29天。)T11列表是集合{1,3,4,5,6,7,8,9,10,11,12}中两个字符ASCII表示的有序列表。有30+日的月份。T7列表是集合{1,3,5,7,8,10,12}中两个字符的ASCII表示的有序列表。有31天的月份。
2-chars List List
Number ASCII Entry Order
---------------------------------
1 -> '01' -> 3130h 4th
2 -> '02' -> 3230h 8th
3 -> '03' -> 3330h 11th
10 -> '10' -> 3031h 1st
11 -> '11' -> 3131h 5th
12 -> '12' -> 3231h 9th
20 -> '20' -> 3032h 2nd
21 -> '21' -> 3132h 6th
22 -> '22' -> 3232h 10th
30 -> '30' -> 3033h 3rd
31 -> '31' -> 3133h 7th最终结果的时间顺序(要求数字反转)自然来自对这些基于文本的表进行排序。
mov si, T31
lodsw
Outer:
push si
mov si, T7
cmp ax, "31"
je @f
mov si, T11
cmp ax, "30"
je @f
mov si, T12
@@:
mov [String+3], ax ;Day
mov [String+6], ah ;Century
mov [String+7], al
lodsw
Inner:
mov [String], ax ;Month
mov [String+8], ah ;Year
mov [String+9], al
mov dx, String
mov ah, 09h ;Print string
int 21h
lodsw
test ax, ax
jnz Inner
pop si
lodsw
test ax, ax
jnz Outer
mov ax, 4C00h ;Exit to DOS
int 21h
ALIGN 2
T7:
db '10011203050708'
dw 0
T11:
db '1001111203040506070809'
dw 0
T12:
db '100111021203040506070809'
dw 0
T31:
db '10203001112131021222031323041424051525061626071727081828091929'
dw 0
String:
db '..........',13,10,'https://codereview.stackexchange.com/questions/237909
复制相似问题