[编程工具]masm32(9.00)+RadAsm2.2.0.9
[调试工具]OD1.10
[调试平台]WinXP/SP2
这次再发一个ASM程序:计算圆周率,比上一个难度大了点儿,主要是完成了N(N>1000000000)位十进制大数的加、减、除运算及显示输出。编写代码用了我一天的业余时间,调试则用了两天,惨啊,明明是4*4*5*DATAMAX/1000==04C4B400h,DATAMAX=1000000000,我写成
mov dword ptr[eax],4*4*5*DATAMAX/1000 竟然没编译出我想要的
mov dword ptr[eax],04C4B400h 让我费了很多时间才发现,编译器有bug??
总算调试通过了,了了我多年的一个心愿。在还没有见过计算机为何物时就知道可以用它计算圆周率,后来用VC++编写了一个计算程序,速度一直不够快,就想着哪一天能用ASM写一个多好,现在总算完成了,速度也比较满意。如果我有时间有精力,而且兴趣还没有消失的话,以后会再写一些东西,希望大家不要打击我,我会慢慢进步的。
;***********************************************************************************************************
;计算原理:
;PI=PI=16x(1/5-1/(5^3/3)+1/(5^5/5)-1/(5^7/7)+...)-4x(1/239-1/(239^3/3)+1/(239^5/5)-1/(239^7/7)+...)
;PI=4x(4x5/25-239/57121)/1-4x(4x5/25^2-239/57121^2)/3+4x(4x5/25^3-239/57121^3)/5-...
;每一个dword型数据只能放9位十进制数,用N个dword数存储9N位计算结果
;y=(4*4*5/25^a),z=(4*239/57121^a),c=(y-z)/a,x+=c 或 x-=c,a+=2(a初始为1),循环计算直到y=0结束
;***********************************************************************************************************
;“计算圆周率.Asm”文件
.386
.model flat, stdcall ;32 bit memory model
option casemap :none ;case sensitive
include 计算圆周率.inc
.code
start:
invoke InitCommonControls
invoke GetModuleHandle,NULL
invoke DialogBoxParam,eax,IDD_DIALOG_MAIN,NULL,addr DlgProc,NULL
invoke ExitProcess,0
;########################################################################
_CalPI proc uses edi esi ebx
LOCAL @hMemX,@pMemX,@hMemY,@pMemY,@hMemZ,@pMemZ,@hMemC,@pMemC
LOCAL @dwDigit,@dwCalLen,@dwA,@dwI,@dwTime
invoke GetDlgItemInt,hWndDlg,IDC_DIGIT,0,0
.if eax<1
invoke SetDlgItemInt,hWndDlg,IDC_DIGIT,1000,0
mov eax,1000
.endif
add eax,4
mov @dwDigit,eax ;要计算的位数
;mov ecx,eax
;shr ecx,7
;add eax,ecx ;要多算几位,因为最后若干位不准确
mov ecx,DATALEN ;要多算几位,因为最后若干位不准确
add eax,ecx
div ecx ;每四字节存放 DATALEN 位十进制的结果
test edx,edx
jz @F
inc eax
@@: shl eax,2
mov @dwCalLen,eax ;内存数组的大小
add eax,4
invoke GlobalAlloc,GMEM_MOVEABLE or GMEM_ZEROINIT,eax
mov @hMemY,eax
invoke GlobalLock,eax
mov @pMemY,eax
mov dword ptr[eax],04C4B400h;4*4*5*DATAMAX/1000,不能写成mov dword ptr[eax],4*4*5*DATAMAX/1000,编译器有bug??
mov ecx,@dwCalLen
inc dword ptr[eax+ecx] ;此为计算结束的标志
invoke GlobalAlloc,GMEM_MOVEABLE or GMEM_ZEROINIT,ecx
mov @hMemZ,eax
invoke GlobalLock,eax
mov @pMemZ,eax
mov dword ptr[eax],038FB6700h;4*239*DATAMAX/1000 同上,编译器有bug??
invoke GlobalAlloc,GMEM_MOVEABLE or GMEM_ZEROINIT,@dwCalLen
mov @hMemC,eax
invoke GlobalLock,eax
mov @pMemC,eax
invoke GlobalAlloc,GMEM_MOVEABLE or GMEM_ZEROINIT,@dwCalLen
mov @hMemX,eax
invoke GlobalLock,eax
mov @pMemX,eax
xor eax,eax
mov @dwI,eax ;循环计数器初始化
inc eax
mov @dwA,eax ;A初始化
invoke GetTickCount
mov @dwTime,eax
;**************************************************************************
CAL_START:
mov ebx,DATAMAX ;开始计算Y/=25
mov esi,25
xor edx,edx
mov ecx,@dwI
mov edi,@pMemY
CAL_Y:
mov eax,edx
mul ebx
add eax,dword ptr[edi+ecx]
adc edx,0
div esi
mov dword ptr[edi+ecx],eax
add ecx,4
cmp ecx,@dwCalLen
jb CAL_Y
mov ecx,@dwI
CAL_SETPOS:
cmp dword ptr[edi+ecx],0
jnz CAL_ISEND
add ecx,4
jmp CAL_SETPOS
CAL_ISEND:
cmp ecx,@dwCalLen
jae CAL_END
mov @dwI,ecx
mov esi,57121 ;开始计算Z/=57121
xor edx,edx
mov edi,@pMemZ
CAL_Z:
mov eax,edx
mul ebx
add eax,dword ptr[edi+ecx]
adc edx,0
div esi
mov dword ptr[edi+ecx],eax
add ecx,4
cmp ecx,@dwCalLen
jb CAL_Z
clc ;开始计算C=Y-Z
mov esi,@pMemC
mov ebx,@pMemY
CAL_C:
lahf
sub ecx,4
cmp ecx,@dwI
jl CAL_CCF
sahf
mov eax,dword ptr[ebx+ecx]
sbb eax,dword ptr[edi+ecx]
jnc CAL_CC
add eax,DATAMAX
stc
CAL_CC:
mov dword ptr[esi+ecx],eax
jmp CAL_C
CAL_CCF:
;sahf
;jc CAL_CDIVA
;dec dword ptr[esi+ecx]
CAL_CDIVA:
xor edx,edx ;开始计算C/=A
mov ecx,@dwI
mov edi,@dwA
mov ebx,DATAMAX
CAL_CA:
mov eax,edx
mul ebx
add eax,dword ptr[esi+ecx]
adc edx,0
div edi
mov dword ptr[esi+ecx],eax
add ecx,4
cmp ecx,@dwCalLen
jb CAL_CA
mov edi,@pMemX
test @dwA,2 ;判断(A/2)是奇数还是偶数
jz CAL_AO
CAL_A1:
lahf ;开始计算X-=C (A/2)是奇数时
sub ecx,4
cmp ecx,@dwI
jl CAL_ACF1
sahf
mov eax,dword ptr[edi+ecx]
sbb eax,dword ptr[esi+ecx]
jnc CAL_AA1
add eax,ebx
stc
CAL_AA1:
mov dword ptr[edi+ecx],eax
jmp CAL_A1
CAL_ACF1:
sahf
jnc CAL_NEXTA
dec dword ptr[edi+ecx]
jmp CAL_NEXTA
CAL_AO:
lahf ;开始计算X+=C (A/2)是偶数时
sub ecx,4
cmp ecx,@dwI
jl CAL_ACFO
sahf
mov eax,dword ptr[edi+ecx]
adc eax,dword ptr[esi+ecx]
cmp ebx,eax
ja CAL_AAO
sub eax,ebx
stc
CAL_AAO:
mov dword ptr[edi+ecx],eax
jmp CAL_AO
CAL_ACFO:
sahf
jnc CAL_NEXTA
inc dword ptr[edi+ecx]
CAL_NEXTA:
add @dwA,2
jmp CAL_START
;**************************************************************************
CAL_END:
invoke GetTickCount
xor edx,edx
sub eax,@dwTime
mov ecx,1000
div ecx
mov ecx,@dwA
shr ecx,1
inc ecx
invoke wsprintf,@pMemC,addr lpStr,ecx,eax,edx
invoke SetDlgItemText,hWndDlg,IDC_TIME,@pMemC
invoke GlobalUnlock,@pMemC
invoke GlobalFree,@hMemC
invoke GlobalUnlock,@pMemY
invoke GlobalFree,@hMemY
invoke GlobalUnlock,@pMemZ
invoke GlobalFree,@hMemZ
mov eax,@dwDigit
add eax,DATALEN
invoke GlobalAlloc,GMEM_MOVEABLE or GMEM_ZEROINIT,eax
mov @hMemC,eax
invoke GlobalLock,eax
mov @pMemC,eax
mov edi,eax
mov ecx,@dwDigit
add ecx,DATALEN-1
mov al,030h
rep stosb
mov edi,@pMemC
mov ecx,10
mov esi,@pMemX
xor edx,edx
mov @dwI,edx
mov ebx,DATALEN
SHOW_DATA:
mov eax,dword ptr[esi] ;显示X中计算结果
SHOW_CHAR:
div ecx
dec ebx
add byte ptr[edi+ebx],dl
xor edx,edx
test eax,eax
jnz SHOW_CHAR
mov eax,@dwI
cmp eax,@dwDigit
jae OK
add esi,4
mov ebx,DATALEN
add @dwI,ebx
add edi,ebx
jmp SHOW_DATA
OK:
mov ecx,@dwDigit
mov edi,@pMemC
mov byte ptr[edi+ecx-1],0
mov cl,byte ptr[edi+2]
mov byte ptr[edi+1],cl
mov byte ptr[edi+2],'.'
invoke GlobalUnlock,@pMemX
invoke GlobalFree,@hMemX
inc edi
invoke SetDlgItemText,hWndDlg,IDC_PI,edi
invoke GlobalUnlock,@pMemC
invoke GlobalFree,@hMemC
ret
_CalPI endp
DlgProc proc hWin:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
mov eax,uMsg
.if eax==WM_INITDIALOG
mov eax,hWin
mov hWndDlg,eax
.elseif eax==WM_COMMAND
mov eax,wParam
.if lParam!=0
mov edx,eax
shr edx,16
.if dx==BN_CLICKED ;按钮消息处理
.if ax==IDC_CAL ;计算
call _CalPI
.endif
.endif
.endif
.elseif eax==WM_CLOSE
invoke EndDialog,hWin,0
.else
mov eax,FALSE
jmp @F
.endif
mov eax,TRUE
@@:
ret
DlgProc endp
end start
;***********************************************************************************
;“计算圆周率.Inc”文件
include windows.inc
include kernel32.inc
include user32.inc
include Comctl32.inc
include shell32.inc
includelib kernel32.lib
includelib user32.lib
includelib Comctl32.lib
includelib shell32.lib
DlgProc PROTO :HWND,:UINT,:WPARAM,:LPARAM
.const
DATALEN equ 9
DATAMAX equ 1000000000
;计算圆周率.dlg
IDD_DIALOG_MAIN equ 101
IDC_GRP1 equ 1003
IDC_STC1 equ 1001
IDC_DIGIT equ 1002
IDC_CAL equ 1004
IDC_TIME equ 1005
IDC_PI equ 1006
;计算圆周率.Rc
MY_ICON equ 10
;#########################################################################
.data?
hWndDlg HWND ?
;#########################################################################
.data
lpStr db '计算%d次,用时%d.%d秒',0
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!