汇编网首页登录博客注册
goal00001111的学习博客
博客首页博客互动【做检测题】论坛求助

我的博客

个人首页 |  我的文章 |  我的相册 |  我的好友 |  最新访客 |  文章收藏 |  论坛提问 |  友情链接 |  给我留言  
图片载入中
  •  --
  • 『姓名』:                    
  • 『性别』:保密  『发送消息
  • 个人说明:当飞鸟失去飞翔的欲望,翅膀也会变成累赘;
    当理想与激情共舞,凡人也能成为英雄.
  • 详细信息『加为好友』
学习动态
好友圈

[2007-12-23 19:41] 筛法求素数

图片载入中
筛法求素数

以前用c语言写过筛法求素数。方法是使用一个辅助数组,把每个自然数的标志存储起来,素数标志为0,非素数标志为1。我设置辅助数组的类型为char类型,这样每个元素占一个字节,由于内存有限,存储不了多少元素,使得程序存储的素数数量非常有限。当时想过用一个字节来存储一个标志,实在是太浪费了,如果能够用一个位来存储该多好啊。现在学习了汇编语言,我可以用一个位来存储素数标志了,于是苦思冥想好几天,写了改,改了写,终于程序成型了。
        当然,程序还有很多不如意的地方,如代码臃肿,可读性差等等。希望通过更多的学习,能够得到更好,更精练,更健壮的代码。
        代码很长,很难入眼。如果您能够完整阅读并提出建议,我将感激不尽!

C代码:
#include<stdio.h>
#include<stdlib.h>

#define N 2000

int Collect_sushu(long data[]);  /*把2-N的所有素数存入数组中*/ 

int main(void)
{
        long sushu[N]={0};     /*用来存储2-N的所有素数*/
        int n = Collect_sushu(sushu);  /*把2-N的所有素数存入数组中*/        
    int i;
    for (i=0; i<n; i++)
        printf("%d\t", sushu[i]);
                        
   system("pause");        
   return 0;
}

int Collect_sushu(long data[])
{
    char sushu[N] = {0};
        long n, i;
        int sum = 0;
        
        for (n=2; n<=N/2; n++)
        {
                if (sushu[n] == 0)
                        for (i=n+n; i<=N; i+=n)
                                sushu[i] = 1;
        }
        
        for (n=2; n<=N; n++)
      if (sushu[n] == 0)
         data[sum++] = n;        
    
    return sum;
}

汇编代码:
assume cs:code, ds:data, es:lib

data segment
     MAX dd 2000            ;自然数的范围1-data:0 ,可自由更改,不能超过7FFFBH 
     dw 800 dup (0)
data ends

lib segment
    ;从左到右分别用来测试1~8位的测试数据,0h没有用 
    db 00h, 80h, 40h, 20h, 10h, 08h, 04h, 02h, 01h;测试各位是否为1 
    db 00h, 7fh, 0bfh, 0dfh, 0efh, 0f7h, 0fbh, 0fdh, 0feh;测试各位是否为0 
    db 01fffh dup (0);用来存储与各个自然数对应的位,0表示素数,1为非素数 
lib ends

primeData segment
    db 20h dup (0);存储临时素数字符串 
PrimeData ends

code segment
Main:
     mov ax, data
     mov ds, ax
     mov ax, lib
     mov es, ax
     
     call GetPrime    ;获取素数,并存储在data中 
     
     ;在屏幕中输出素数 
     mov ax, primeData
     mov ds, ax 
     mov ax, data
     mov es, ax 
     mov bx, 0         ;从bx行开始输出 
     mov bp, 4         ;从素数2开始输出 
MA:
     mov ax, es:4[bp]  ;指向当素数 
     mov dx, es:4[bp+2]  
     mov si, 0
     
     cmp dx, es:[2]     ;判断是否越界 
     jnb MC
     
MB:     
     call Dtoc          ;完成dword型数据到字符串的转化,并把字符串存储在primeData中  
     
     mov ax, bp     
     mov dl, 40         ;每个数字占4个字节,共10个数字 
     div dl
     cmp ah, 0          ;判断余数是否为0,为0则表示已经输满10个,跳到下一行 
     jne SameLine       ;否则直接输出该素数                                                 
      
     inc bl             ;每输出10个数字,跳转到下一行  
SameLine: 
     mov al, ah         ;余数,即该数字所处列数 
     mov ah, 0
     mov dl, 2          ;每个数据占8位,即2×bp,bp每次增4
     mul dl    
     mov dh, bl         ;行序
     mov dl, al         ;列序 
     mov cl, 00001111b  ;颜色
     mov si, 0
     
     call ShowStr       ;显示字符串
     
     add bp, 4
     jmp MA

MC:      
     cmp ax, es:[0]      ;判断是否越界,确定输出范围    
     jnb EndMain
     jmp MB
     
EndMain:    
     mov ax, 4c00h       ;程序结束,返回到操作系统系统
     int 21h
;//////////////////////////////////////////////////////////////////////////
;子程序描述:
;名称:GetPrime
;功能:找出1~ds:[0]内的素数,并存储在data段 
;参数:dd类型数ds:[0]表示查找的范围,不能超过7FFF0H。 
;返回:ds:[4]开始的dd类型数据,同时lib[18]段中也存储了相关信息 
GetPrime:
     push ax           ;子程序用到的寄存器入栈                                    
     push bx
     push cx
     push dx
     push si
     push di
     push bp
     
     mov bx, 0         ;存储自然数的高8位 
     mov cx, 2         ;存储自然数的低8位,从2开始判断各个自然数是否为素数 
     
PA:
     mov dx, bx        ;存储自然数的高8位
     mov ax, cx        ;存储自然数的低8位
     xor bp, bp
     call JudgeZeroOrOne;测试当前自然数(存储在dx,ax中)是否已经被测试过                 
     cmp bp, 0
     jne PD            ;若已经测试过则不必重复测试       
PB:  
     add ax, cx        ;将当前自然数的整数倍标记为非素数 
     adc dx, bx
     cmp dx, ds:[2]    ;不可超出最大范围 
     jnb PE  
                                             
PC:      
     mov bp, 1
     call SetZeroOrOne  ;将当前自然数的整数倍标记为非素数,所在的位为1 
     jmp PB
     
PD:
     add cx, 1          ;测试下一个自然数
     adc bx, 0
     cmp bx, ds:[2]     ;判断高位字节是否超出范围 
     jnb PF             ;若相等或超出则判断低位字节 
     jmp PA             ;若未超出,测试下一个自然数

PE:
     cmp ax, ds:[0]     
     ja PD
     jmp PC
     
PF:
     cmp cx, ds:[0]
     ja PG
     jmp PA

PG:                                                       
     call ShowPrime ;将素数存储到data段 
     
     pop bp         ;子程序用到的寄存器出栈
     pop di
     pop si
     pop dx
     pop cx
     pop bx
     pop ax
     ret
;//////////////////////////////////////////////////////////////////////////
;子程序描述:
;名称:ShowPrime
;功能:将素数存储到data段 
;参数:在es:18[bx]中存储了表示某个数是否未素数的信息
;返回:data段
ShowPrime:
     mov bx, 0
     mov di, 0
     
SA:
     mov si, 1      ;从第一位开始测试,从左边数起                                                                   

SB:
     cmp si, 8      ;测试各个位,共8位 
     ja SD
     
     mov al, es:[si]
     test es:18[bx], al
     jne SC
     
     mov ax, 8       ;n = 8*bx + si 
     mov dx, 0
     mul bx
     add ax, si
     adc dx, 0
     mov 4[di], ax
     mov 4[di+2], dx
     
     add di, 4
SC:
     inc si
     jmp SB
     
SD:
     mov ax, ds:[0]  ;总共有ds:[2]ds:[0]个自然数,即需要ds:[2]ds:[0]/8个字节空间 
     mov dx, ds:[2]
     mov cx, 8
     call Divdw

     inc bx
     cmp bx, ax
     jnb SE
     jmp SA

SE:
     ret
;//////////////////////////////////////////////////////////////////////////
;子程序描述:
;名称:JudgeZeroOrOne
;功能:测试从指定位置开始的内存中,第n(cx)位(用二进制表示)是0还是1,从1开始数 
;参数:dx,ax表示被测试的第n位
;返回:bp,若第n位为0,则bp=0,否则等于1    
JudgeZeroOrOne:
     push ax
     push bx
     push cx
     push dx
     push si

     mov cx, 8
     call Divdw

     mov bx, ax     ;第bx个数      
     mov si, cx     ;第si位数字(2进制)
     cmp si, 0
     je Judge8
     
     mov al, es:[si]
     test es:18[bx], al  ;测试第bx个数对应的位,除了第8位
     je EndJudge   ;是0直接返回,否则令bp=1,作为标记                              
     mov bp, 1                                                                       
     jmp EndJudge
     
Judge8:
     mov al, es:[8]
     test es:18[bx-1], al;测试第bx个数对应的位,仅限于第16位 
     je EndJudge   ;是0直接返回,否则令bp=1,作为标记                              
     mov bp, 1                  
EndJudge:
     pop si
     pop dx
     pop cx
     pop bx  
     pop ax  
     ret
;//////////////////////////////////////////////////////////////////////////
;子程序描述:
;名称:SetZeroOrOne
;功能:从指定位置开始的内存中,设置第n(cx)位(用二进制表示)为指定的0或1 
;参数:dx,ax表示被设置的第n位,bp表示指定的设置值,0或1 
;返回:无 
SetZeroOrOne:
     push ax
     push bx
     push cx
     push dx
     push si

     mov cx, 8
     call Divdw

     mov bx, ax     ;第bx个数      
     mov si, cx     ;第si位数字(2进制)
     cmp si, 0
     je Set8
     
     cmp bp, 1
     je SetOne1
     mov al, es:9[si]
     and es:18[bx], al  ;设置第bx个数对应的位,除了第8位                                                                     
     jmp EndSet
SetOne1:     
     mov al, es:[si]
     or es:18[bx], al  ;设置第bx个数对应的位,除了第8位                                                                     
     jmp EndSet
     
Set8:
     cmp bp, 1
     je SetOne2
     mov al, es:9[8]
     and es:18[bx-1], al;设置第bx个数对应的位,仅限于第16位 
     jmp EndSet
SetOne2:     
     mov al, es:[8]
     or es:18[bx-1], al;设置第bx个数对应的位,仅限于第16位 
                
EndSet:
     pop si
     pop dx
     pop cx
     pop bx  
     pop ax  
     ret
;//////////////////////////////////////////////////////////////////////// 
;完成dword型数据到字符串的转化。
;子程序描述:
;名称:Dtoc
;功能:将dword型数据转变为表示十进制的字符串,字符串以0为结尾符。
;参数:(ax)=dword型数据的低16位
;         (dx)=dword型数据的高16位
;         ds:si指向字符串的首地址
;返回:无
Dtoc:    
     mov cx, 10             ;以10为除数 
     call Divdw             ;进行不会产生溢出的除法运算
     
     add cx, 30h            ;将余数转化成十进制数 
     push cx                ;将十进制形式存储的余数入栈       
     mov cx, ax 
     or cx, dx
     jcxz SaveToData        ;被除数高位和低位均为0则不再递归调用函数 

     call Dtoc            ; 被除数不为0则递归调用Dtoc子程序 
      
SaveToData:  
     pop cx                                
     mov [si], cl          ;余数以十进制形式存储到data段              
     inc si
     mov byte ptr [si], 0  ;以0结束 
     ret
;///////////////////////////////////////////////////////////////////////////
;解决除法溢出的问题
;子程序描述:
;名称:Divdw
;功能:进行不会产生溢出的除法运算,被除数为dword型,除数为word型,结果为dword型。
;参数:(ax)=dword型数据的低16位
;          (dx)=dword型数据的高16位
;          (cx)=除数
;返回:(ax)=结果的低16位
;          (dx)=结果的高16位
;          (cx)=余数
Divdw:  
        push bx        ;子程序用到的寄存器入栈
        push ax        ;被除数的低16位入栈
         
        mov ax,dx      
        mov dx,0
        div cx         ;先用被除数的高16位除以除数 
        mov bx,ax      ;将int(H/N)存储到bx中,rem(H/N)自动存储到dx 
         
        pop ax         ;被除数的低16位出栈 
        div cx         ;用被除数的低16位除以除数
        mov cx,dx      ;将余数存储到cx 
        mov dx,bx      ;将商的高16位存储到dx,商的低16位自动存储到ax 

        pop bx         ;子程序用到的寄存器出栈
        ret   
;////////////////////////////////////////////////////////////////////////   
;显示字符串
;子程序描述:
;名称:ShowStr
;功能:在指定的位置,用指定的颜色,显示一个用0结束的字符串。
;参数:(dh)=行号(取值范围0~24), (dl)=列号(取值范围0~79),(cl)=颜色,ds:si指向字符串的首地址。
;返回:无
ShowStr:                  
     push bx               ;子程序用到的寄存器入栈 
     push cx
     push es
     
     mov ax, 0b800h
     mov es, ax            ;显示缓冲区
     
     mov ax, 160           ;计算起始行:行号*160
     mul dh
     mov bx, ax            ;存储起始行 
     
     shl dl, 1               ;计算起始列:列号*2
     xor dh, dh
     mov di, dx            ;存储起始列 

     mov ah, cl            ;存储字符属性 
     
     xor cx, cx
Show:
     mov cl, [si]
     jcxz EndShowStr       ;遇到0结束 

     mov al, cl            ;存储字符ASCII码 
     mov es:[bx][di], ax   ;显示字符 
     add di, 2
     inc si
     jmp Show
     
EndShowStr:
     pop es                ;子程序用到的寄存器出栈
     pop cx
     pop bx
     ret
;//////////////////////////////////////////////////////////////////////////////////   
code ends
end Main
评论次数(3)  |  浏览次数(1559)  |  类型(原创文章) |  收藏此文  | 

[  游客   发表于  2007-12-24 08:58  ]

先存下来

[  fishboy   发表于  2007-12-24 10:39  ]

岂止一个牛字了得!!

[  游客   发表于  2009-01-14 12:24  ]

太强了

 
 请输入验证码  (提示:点击验证码输入框,以获取验证码