标题:大家来写写汇编小玩意(三)
取消只看楼主
Valenciax
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:11
帖 子:337
专家分:2462
注 册:2016-5-15
结帖率:100%
已结贴  问题点数:20 回复次数:11 
大家来写写汇编小玩意(三)
之前提了几个小题目,考的是写最短代码,这次来点别的,玩玩解题能力。

题目一:
先来百度:
考拉兹猜想,又称为3n+1猜想、角谷猜想、哈塞猜想、乌拉姆猜想或叙拉古猜想,是由日本数学家角谷静夫发现,是指对于每一个正整数,如果它是奇数,则对它乘3再加1,如果它是偶数,则对它除以2,如此循环,最终都能够得到1。
取一个数字。
如n = 6,根据上述公式,得出 6→3→10→5→16→8→4→2→1 。(步骤中最大的数是16,共有8个步骤)。
如n = 11,根据上述公式,得出 11→34→17→52→26→13→40→20→10→5→16→8→4→2→1。(步骤中最大的数是52,共有14个步骤)
考拉兹猜想称,任何正整数,经过上述计算步骤后,最终都会得到 1 。

题目来了。
输入:
输入需要验证角谷猜想的数n,0<n<1000000000(10亿),直到输入0或回车为止。

输出:
从数字n开始,依次输出经过变换后得到的每一个数字,数与数之间用“->”连接,直到输出1为止步。统计步骤中最大的数字m以及所需的步骤数x,然后在下一行输出如下引号中的信息:“Max is m and we need x steps.”。
对于步骤数的规定:我们约定,经过一次运算为1步,比如,在下面的输入样例中,从11到34就是第1步,如此循环,直到最后数字变成1为止。

比如:
11
输出:
11->34->17->52->26->13->40->20->10->5->16->8->4->2->1
Max is 52 and we need 14 steps.

其实逻辑挺简单的,这是我草草写的一个。



题目二:
1. 键盘输入的两个日期(日期为8位数的年月日),求出之间相差几天。
2. 在输入日期前要有提示信息(如:Input First Date / Input Second Date)

这题也很简单,重点是计算闰年,设定一个参考点....验证可用excel
一如既往,我也写了一个。



有趣兴可以写写,贴出代码,或者说说想法也可以。



搜索更多相关主题的帖子: 百度 数学家 正整数 最大的 日本 
2016-06-26 08:30
Valenciax
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:11
帖 子:337
专家分:2462
注 册:2016-5-15
得分:0 
回复 2楼 wmf2014
谢谢班竹参与,国内汇编论坛一向冷清,反而国外比较热闹些,仍然有一群热心人写,他们许多人由dos写到win32和win64,x86写到sse4………

题一不会很复杂,64k内自然可以,至于如何读入大数,如何显示大数(甚至几百几千位),我会在接下的贴子跟大家分享,当然若有人写出来,那就更好了。

题二较难些,我会随后贴出代码和一些心得。



2016-06-26 23:02
Valenciax
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:11
帖 子:337
专家分:2462
注 册:2016-5-15
得分:0 
回复 2楼 wmf2014
班竹常提到的32BIT,其实之前写的一直是DOS的16BIT代码,只是偶然用到32BIT暂存器而已,题一写的也是DOS程式。一时起意,刚才用WIN32的控制台写了一个,用的是MASM32安装包里的MASM32 Editor编写,因为利用宏,输入输出借用了函数库,反而比DOS简单的多,更且可以用中文。
程序代码:
NLimit equ 999999999
include \masm32\include\masm32rt.inc
.stack 500h
.data
     Result dd 0,0
     myStep dd 0,0
     MaxValue dd 0,0
     output db "%I64i", 0 ;64bit format
     crtf db 10,13,0
.code
start:
     xor eax,eax
     lea edi,Result
     mov ecx,6
     rep stosd
     invoke atol, input(10,13,"角谷猜想 (1-999,999,999):") ;get input 
     cmp eax,1  ;is it 1
     jb quit ; less then , quit
     cmp eax,NLimit ; is it input limit ?
     ja start ;yes
     mov Result,eax ;save
next:  
     lea esi,Result  ;get last value address
     invoke crt_printf, offset output, qword ptr [esi] ;print it
     cmp Result,1  ;is it 1 ?
     jz next9  ;yes
     print ""  
     mov eax,Result ;get last value
     test eax,1  is it Even
     jz next2 ;yes , EVEN !
     ;-- ODD --
     add eax,Result 
     add eax,Result
     inc eax  ; x 3 + 1
     cmp eax,MaxValue ;最大值 ?
     jbe next4 ;no
     mov MaxValue,eax ;save it 最大值
     jmp short next4 
next2: ; -- EVEN
     shr eax,1  ; /2
next4:
     mov Result,eax  ;save it 
     inc myStep ;加步
     jmp short next ; looping....
next9:
     invoke crt_printf,addr crtf  ;other method to print 回车
     print "最大值 "
     lea si,MaxValue
     invoke crt_printf, offset output, qword ptr [esi] ;print最大值
     print ""
     lea si,myStep
     invoke crt_printf, offset output, qword ptr [esi] ;print 步
     print ""
     jmp start
quit:
     exit  ;結束
end start



[此贴子已经被作者于2016-6-27 10:06编辑过]

2016-06-27 07:53
Valenciax
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:11
帖 子:337
专家分:2462
注 册:2016-5-15
得分:0 
回复 7楼 wmf2014
对的,不用考虑太烦琐输入输出...
Masm32并不是微软官方出品,是一群有心人在维护,它们整合了masm32/64版,加了许多有用的宏,借用许多c标准函数库,比如上面5楼的atol、input和print等就是宏,atol是字符转long的意思,传回EAX的32bit值,一句宏相当于十数条汇编指令(我的dos版,光输入32值连容错代码就要三十多行),赶得上高阶语言的方便!

[此贴子已经被作者于2016-6-27 13:33编辑过]

2016-06-27 13:32
Valenciax
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:11
帖 子:337
专家分:2462
注 册:2016-5-15
得分:0 
先发个子程序,若用int21h,ah=0AH读入字符串,这子程序能把它
转换成32bit数值传回,换言之,最多读到FFFFFFFFh,即4294967295

分两个版本
版本一只用16bit暂存器,由dx:ax传回
版本二用32bit暂存器,由EAX传回
使用方法,si指向输入缓冲,呼叫子程式即可
程序代码:

 lea dx,InputBuffer  ;指向输出缓冲
  mov ax,0c0ah  ;输入函数,先清空键盘缓冲
  int 21h

 ..

 ..

 ..

 lea si,InputBuffer + 2

 Call GetValue32 或 Call GetValue32x



16bit暂存器版
程序代码:
;--------------------------------------------------
;转值子程序,把输入的10进制文字转成16进制
;输入:ds:si数字字符串起点,以0dh或0结束
;输出:ds:ax=转换后的32进制值,cf=1表示有非数字字符
;若输入值少于65535,则dx=0
;--- 16bit暂存器版---------------------------------
GetValue32: 

 push bx

 push cx

 push si

 push di

 push bp

 xor cx,cx

 xor di,di

 xor dx,dx

 mov bx,10
d10:

 lodsb

 cmp al,0dh ;若以0d为结束符,启用这句,关闭下句
 ;cmp al,0  ;若以0为结束符,启用这句,关闭上句
 jz d20

 sub al,'0'

 cmp al,9

 jbe d15
d12:

 stc

 jmp short d99
d15:

 cbw

 mov bp,ax ;store to bp
 mov ax,cx ;get cx
 mul bx ;x 10
 mov cx,ax ;store to key hi
 mov ax,bp ;restore from bp
 xchg ax,di ;get key lo
 mul bx ;x 10
 xchg ax,di ;store to key lo
 add di,ax ;add low byte to key lo
 adc cx,dx ;add to key hi
 jnc d10

 jmp short d12
d20:

 mov dx,cx

 mov ax,di

 clc
d99:

 pop bp

 pop di

 pop si

 pop cx

 pop bx

 ret


32bit暂存器版
程序代码:
;--- 32bit暂存器版---------------------------------
;转值子程序,把输入的10进制文字转成16进制
;输入:ds:si数字字符串起点,以0dh或0结束
;输出:eax=转换后的32进制值,cf=1表示有非数字字符
;若希望由ds:ax传回,可加三句于ret之前
; mov edx,eax
; shr edx,16
; and eax,0000FFFFh
;--------------------------------------------------
.386
GetValue32X: 

 push ebx

 push edi

 xor ebx,ebx

 mov edi,10
GetV10:

 lodsb     ;指向起点
 and eax,000000ffh ;清除高bit,保留AL
 cmp al,0dh ;若以0d为结束符,启用这句,关闭下句
 ;cmp al,0  ;若以0为结束符,启用这句,关闭上句
 jz Getvx

 sub al,'0'

 cmp al,9

 ja Getvy

 xchg ebx,eax  ;交换
 mul edi

 add ebx,eax  ;累加
 jmp short GetV10
Getvx:    

 mov eax,ebx ;ascii转值后由eax转回
 clc ;成功cf=0
 jmp short Getvz
Getvy:

 stc  ;错误 cf=1
Getvz:

 pop edi

 pop ebx
; mov edx,eax
; shr edx,16
; and eax,0000FFFFh
 ret



[此贴子已经被作者于2016-6-27 22:06编辑过]

2016-06-27 22:00
Valenciax
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:11
帖 子:337
专家分:2462
注 册:2016-5-15
得分:0 
再发一个印出32位的代码

使用方法
 mov dx, yyyy
 mov ax, xxxx
 call  OutDec  ;印出dx:axh的 32值,若只输ax, dx必先清0
程序代码:
;-----以十进制输出DX:AX的32BIT值------
;输入 :dx=32bit高位,ax=32bit低位
;输出 :标准输出设备(屏幕)
;破坏暂存器:除dx,ax外,无
;注:若只输ax,dx先清0
;-------------------------------------
OutDec:     
    push bx
    push cx
    push si
    push bp
    xor cx,cx
    xchg bp,dx
    mov si,10      ;div by 10
    mov bx,30h  ;'0'
OutDec1:    
    or bp,bp    ;是否已除完高位?
    jz OutDec3  ;yes
    xchg bp,ax
    xor dx,dx
    div si   ; /10 ,利用除10取余法,逐步push入个位
    xchg bp,ax
    div si
    or dl,bl  ;转ascii
    push dx
    inc cx
    jmp short OutDec1
OutDec3:    
    xor dx,dx
    div si
    or dl,bl
    push dx
    inc cx
    or ax,ax  ; 是否已除完低位?
    jnz OutDec3  ;no
OutDec4:    ;到此,高低已除完! cx=有效个数
    pop ax   ;后入先出,分别pop回最前位,然后一直到个位
    int 29h  ;可改用int10h,ah=0eh,印出al, 或pop dx,用int21h,ah=2印出dl
    loop OutDec4
    pop bp
    pop si
    pop cx
    pop bx
    ret
;--------------------------------------


[此贴子已经被作者于2016-6-28 09:54编辑过]

2016-06-28 09:49
Valenciax
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:11
帖 子:337
专家分:2462
注 册:2016-5-15
得分:0 
题一有了9/10楼的输入/输出子程序,写代码就不是难事,再不明白可参考5楼的写法。

接下来说说题二
重点是解决闰年的判断,先来一段百度
西元年分除以400可整除,为闰年。
西元年分除以4可整除但除以100不可整除,为闰年。
西元年分除以4不可整除,为平年。
西元年分除以100可整除但除以400不可整除,为平年

好了,有了定义,下面我写了一段判断闰年的子程序。

用法:
MOV AX,YEAR (待查的年份)
CALL LeapYear

传回AX=1(闰年)
传回AX=0(非闰年)

程序代码:
LeapYear:  ;輸入AX=年份,輸出AX=1(閏年),AX=0(非閏年)
 push bx

 push dx

 push si

 mov si,ax

 mov bx,400 ;年份除以400餘數等于零,為閏年
 mov dx,0

 div bx

 or dx,dx ;是否0 
 jz last ;餘數為零,直接輸出閏年 
 mov dx,0 

 mov bx,4 ;除以400餘數不等于0,進行除以4餘數是否等0的判斷
 mov ax,si 

 div bx

 or dx,dx  ;是否0
 jz ok ;除以四餘數等于0,跳往除以100餘數是否等0的判斷
over:
;除以四餘數不等于0,則不為閏年,結束 
 mov ax,0

 jmp nil

ok: mov bx,100 ;除以100餘數為零,則不為閏年,餘數不為零,則為閏年
 mov dx,0 

 mov ax,si 

 div bx

 or dx,dx ;是否0
 jz over
last:

 mov ax,1
nil:

 pop si

 pop dx

 pop bx

 ret


然后是2月的28/29问题
我们先建立一个月份的天数阵列
monthday dw 31,28,31,30,31,30,31,31,30,31,30,31 ;月份天数

这其中,除了二月都是恒定的,但可以根据使用者输入的年份去加或不加二月。
若是闰年,二月的28加1,否则不加。
拿这个表格,还可以判断使用者输入的日期是否合法,若输入2015/2/29,查知该年2月是28天,不符!
若输入2016/2/29,查知该年2月是29天,通行!

接下来,我们定义一个参考点,就1000年吧,若输入2016/2/29。
计算方法是:
1.
定义一个双字的总年份 TOTALYEAR DD 0
由年份1000起,AX=年份,呼叫LeapYear子程序得知该年是否闰年,
是则TOTALYEAR + 366, 否则 + 365
年份+1,回到1再加,直到输入年份的前一年,2015。
2.
计算该年的总天数。
由输入月份的前一月加起,根据表格monthday的该月天数加,直加到1月,再加上输入日期,
就是该年的总天数。
3.
该年的总天数加上1项的天数就是[使用者输入年月日]和1000/1/1相差的天数。
4.
将使用者输入的两个日期相减,就是两个日期的[相差值]。
5.
印出



原理说完了,有了LeapYear子程序,还怕写不出来?

2016-06-29 07:37
Valenciax
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:11
帖 子:337
专家分:2462
注 册:2016-5-15
得分:0 
回复 14楼 hu9jj
刚贴了点东西就看见班竹回话了,早上好
2016-06-29 07:40
Valenciax
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:11
帖 子:337
专家分:2462
注 册:2016-5-15
得分:0 
回复 18楼 wmf2014
很好,指令也很精简了

我也发一个dos版的,用的是32位暂存器(1-999999999),结果就是1楼的图,和5楼的不同,5楼是windows的控制台程式,只能在windows下运行,这个dos版在任何环境都可运行(win7/8 64bit需要dosbox或模拟器)
和楼上班竹的一样,这是com格式
Masm5.x要exe->com
Exe2bin xxx.exe
Masm6.1
ML /AT xxx.asm
程序代码:
    NLimit equ 999999999
    code segment
    assume cs:code,ds:code,es:code,ss:code
    org 100h
start:jmp short begin
     InputBuffer db 10,0,10 dup (0)
     DispStr db 10,13,'Input a number (1-999,999,999):$'
     CurrentValue dd 0
     Step dd 0
     MaxValue dd 0
     Dispstr1 db 10,13,'Max is ','$'
     Dispstr2 db ' and we need ','$'
     Dispstr3 db ' steps.','$'
     CtrF db 10,13,'$'
begin:cld   ;正向
    Call GetUserInput  ;输入子程序
    ;则对它乘3再加1,如果它是偶数,则对它除以2,如此循环,最终都能够得到1。  
.386
    cmp EAX,0
    jz QuitX
    mov  CurrentValue,EAX
    lea dx,CtrF
    mov ah,9
     int 21h
next:mov eax,CurrentValue
    xor edx,edx
    call print_dec 
    cmp eax,1
    jz quit
    push eax
    mov al,26     ;->
    int 29h
    pop eax
    test eax,1
    jz next3 ;偶数
    ;奇数
next2:add CurrentValue,eax
    add CurrentValue,eax
    inc CurrentValue
    mov eax,CurrentValue
    cmp eax,MaxValue
    jbe next4
    mov MaxValue,eax
    jmp short next4
next3:   ;偶数
    shr eax,1  ;/2
    mov CurrentValue,eax
next4:inc Step
    jmp short next
quit:lea dx,Dispstr1
    call DispProc
     mov eax,MaxValue
    xor edx,edx
    call print_dec 
    lea dx,Dispstr2
    call DispProc
     mov eax,Step
    xor edx,edx
    call print_dec 
    lea dx,Dispstr3
    call DispProc
    mov ah,7 ;暂停
    int 21h
quitx:mov ah,4ch ;离开
    int 21h
;--------------------------------------------------------------------------
;output EDX:EAX 输出64bit子程序 (0-18446744073709551615)
print_dec:pushad
     xor ecx,ecx
     xchg ebp,edx 
     mov esi,10 ;div by 10
     mov ebx,30h
print_dec1:or ebp,ebp
     jz print_dec3
     xchg ebp,eax
     xor edx,edx
     div esi
     xchg ebp,eax
     div esi
     or dl,bl
     push dx
     inc ecx
     jmp short print_dec1
print_dec3:xor edx,edx
     div esi    
     or dl,bl
     push dx
     inc ecx
     or eax,eax
     jnz print_dec3
print_dec4:pop ax
     int 29h
     loop print_dec4
     popad
     ret
;--------------------------------------------------------------------------
;转值子程序,把输入的10进制文字转成16进制
;输入:ds:si数字字符串起点,以0dh结束
;输出:eax=转换后的16进制值(32bit),cf=1表示有非数字字符
GetValue:push ebx
     push edi
     xor ebx,ebx
     mov edi,10
GetV10:lodsb     ;指向起点
     and eax,000000ffh ;清除高bit,保留AL
     cmp al,0dh ;回车?
     ;cmp al,0  ;-----zero
     jz Getvx
     sub al,'0'
     cmp al,9
     ja Getvy
     xchg ebx,eax  ;交换
     mul edi
     add ebx,eax  ;累加
     jmp short GetV10
Getvx:mov eax,ebx ;ascii转值后由eax转回
     clc ;成功cf=0
     jmp short Getvz
Getvy:stc  ;错误 cf=1
Getvz:pop edi
     pop ebx
     ret
;-------------------------------------------------------------------
GetUserInput: mov ah,9
     lea dx,DispStr ;提示
     int 21h
     lea dx,InputBuffer  ;指向输出缓冲
     mov ax,0c0ah  ;输入函数,先清空键盘缓冲
     int 21h
     lea si,InputBuffer + 2
     mov cx,0  
     mov cl,[si-1] ;取实际输入数
     jcxz GetUx  ;无输入
     Call GetValue ;取值子程序,ax传回该值,cf=1表示错误,可能输入非数字
     jc GetUserInput  ;输入错误,非数字
     cmp eax,NLimit   ;999999999 ?
     ja GetUserInput
     ret
GetUx:xor eax,eax
     ret
;-------------------------------------------------------------------
DispProc:mov ah,9
    int 21h
    ret
;-------------------------------------------------------------------
CODE ENDS
END START


[此贴子已经被作者于2016-6-30 13:06编辑过]

2016-06-30 12:56
Valenciax
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:11
帖 子:337
专家分:2462
注 册:2016-5-15
得分:0 
回复 20楼 wmf2014
这个我也实作过了,但有限制的,好像是1970-2xxx,这个xxx记不起是什么,
但不会是999这么大,我改用计算就是不爽这个限制,基本上计算并无限制,
公元到几万年都没问题。

另有一点, int 2ah/2ch这些日期函数,在dosbox或模拟器或freedos等系统不一定有作用,结果是让人气结,不如直接计算。
2016-06-30 17:36



参与讨论请移步原网站贴子:https://bbs.bccn.net/thread-466366-1-1.html




关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.047004 second(s), 9 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved