注册 登录
编程论坛 VFP论坛

用删除法编写一个制作素数表的vfp程序

独木星空 发布于 2021-09-13 21:47, 12491 次点击
标记法主题思路,标记法是把符合条件的标记为假flase,而不符合条件的标记为真,在vfp中是这样实现这个过程的,先用
本轮参与运算的,求出最大开方值,然后查出所在记录条位置,由此记录条作为筛选循环总次数,第一次现由源数据,加周
期值9699690(即2*3*5*7*11*13*17*19=9699690,一次性调入1658880个数据(就这些需要判断是否为素数,其余的已经被排
除掉了)。有了循环次数,有了被筛选数据,进入主要循环体,先调入第一个素数,划掉其倍数,其余的存入数据b(从数据
源先调入数据a),然后调入第二个素数,排查数据b中符合条件的,剩余的存入数据a(当然每次存数据以前,要把数据表先
清空),循环往始,直到调入最后一个素数为止。然后把最后存的数据,抄写到素数结果表。
进入下一批数据调入,即把数据源加一个周期值9699690,先判断开方值,把小于等于开方值的记录条作为本次的素数调入个
数的依据(即本次的排查次数),进入同样的循环,获得结果,抄写到素数结果表。直到全部周期结束为止。
外循环为周期数,内循环为开方值记录条数减去素数19前的个数8,比方开放值以内有1000个素数,则内主体循环次数为:
1000-8=992次,当然随着循环周期的扩大,内循环次数增多。内循环单次,需要判断值逐步减少,例如第一次调入1658880个
值,大概有1658880/23=72125数被去掉,1658880-72125=1586755/29=54715数被筛掉,这样下去,越往后被判断数越少。所以
成倒排三角形数据量。把最后剩余的数据存放在素数结果表中即可。
外循环步长9699690,即一次性可以判断这样的自然数段。
最原始的筛法,一个一个的去判断,筛除,也就是都在重复同一项工作,效率低下;而这种算法是一次性调入一个批次的数据(这个批次是一个自然数段落,一个递增周期),是众数,不是一个一个的来,而是一同进入,然后第一次就排除了,最多的数据(因为小素数先参与排查,根据几率均等原则,它的倍数最多)。
157 回复
#2
独木星空2021-09-13 22:29
编写思路:预先制作一个5万以内的素数表,做为内循环调用素数之用,在做一个素数表(盛放素数,即把结果抄写到此表),有一个数据源表,就是基础数据(被2,3,5,7,11,13,17,19筛除过的,剩余自然数(9699690以内,它是一个外循环需要增加的值)),数据源中有2*4*6*10*12*16*18=1658880个数据,每增加一次外循环,所有数据源中的数加9699690一次,即被筛选数据=数据源中的数+(i-1)*9699690,i为外循环值;判断每批次调入的最大值的开方值,用count 函数求出小于等于它的记录条数,比如外循环值i=1时,数据源中的最大值9699689,开方值3114.4,在素数表中找到小于等于它的记录条数:443(最后一个满足条件的素数是3109),把此数443-8(不必检查素数2,3,5,7,11,13,17,19这八个素数,因为数据源的数据就是它们制作出来的,也就是说已经通过了它们的筛选,不可能还有它们中的因子,外循环每次增加值是它们的公倍数9699690,所以仍就不含其因子),这样内循环就是443-8=435,把指针移到记录条9的位置(go 9→即从素数23开始),建一个表"数据a",再建一个表"数据b",每一次外循环开始,先清除“数据a”的记录值(只留表结构,把数据标记删除,然后在彻底删除),之后把数据源的记录值+(i-1)*9699690追加新记录,这步完成后,进入内循环子程序,调入第一个素数23(go 9),判断“数据a”的数值是否整除它,整除的直接跳过,不做存表处理,不能整除的,在“数据b”中增加一条记录,把值赋给“数据b”中新增记录条,然后第二个素数调入,以“数据b”为参考,进行同样的处理,循环往复,直到调入本次内循环最后一个素数,然后把最终结果抄写到素数表结果中存储。进入下一个外循环。
#3
独木星空2021-09-13 22:31
所用素数表和数据源表:
只有本站会员才能查看附件,请 登录
只有本站会员才能查看附件,请 登录
#4
独木星空2021-09-13 22:55
大概思路就是这样,相关表和数据已经有了。把外循环次数控制在2以上即可。
整个思路就是网上的划掉法,把n以内的数据排列好,然后从素数2开始划掉后边2的倍数,接着划掉3的倍数,继续....,划掉最后一个素数的倍数(根号n内的最后一个素数的倍数)。只是把这种方法,做了一个折中方法,如果n值较小,可以一次性处理完成,可是当n较大时,我们可以分段处理,另外为了降低运算时间,提前对每段做了预先处理,因为小素数排除的数比重较大,所以我把处理批次的量定在9699690这个增加周期上,在它每一个周期内只需要处理:2*4*6*10*12*16*18=1658880个数据,占比1658880/9699690=0.171多点,大大节约了时间,在就是一个一个的判断,要比这种成批的计算,费时的多。数据a和数据b是相互替换的,每参与一个素数,它们的记录条都会减少,所以也会大大的缩短时间(不必每次都把所有数据判断一次了,已经不符合的干脆去掉,越来越轻装上阵)。
#5
独木星空2021-09-14 07:11
有人浏览了,没有进行提问,也不知道是否理解问题?有不清楚的地方,我希望大家问出来,我好针对的回答。就是二层循环,外层循环就是成批的调入数据,内循环是主角,虽然没有按网上的把记录条标记真与假,用求余数法去掉了被筛除数,道理是一样的,对于内循环次数也容易获得。不知大家怎么看?
#6
schtg2021-09-14 07:48
学习之中
#7
mywisdom882021-09-14 08:41
语文水平有限,不知道你说什么,你要做什么。。。
#8
独木星空2021-09-14 08:45
回复 6楼 schtg
如果理解了,我希望尽早得到回复。
#9
独木星空2021-09-14 09:14
回复 7楼 mywisdom88
就是用划掉法制作素数表。用筛选法制作素数表,是每调入一个正整数,把它开方值以前的素数都用一遍,中间时,有整除的直接跳出循环,然后筛选下一个值。
而此种方法就是一下子调入一批数(假如100个正整数或者1千个,甚至更多),求出此批次最大一个值的开方数,找到开方值以前的所有素数(即素数≤根号n(n是这批次的最大值)),确定最后一个符合条件的素数所在的记录条,以此记录条作为内循环值(循环次数),因为数据源是经过素数2至19处理的,所以不在做检验,直接从第9个素数23开始,进入内循环即可,所以内循环次数-8,在内循环中有两个表,目的是盛方待处理数据,每次外循环进入前,先把数据调入数据a表,然后调入第一个条件素数23,进行筛选,把23的倍数去掉后,剩下的被筛选数据放到数据b表中,调入下一个素数29,筛选数据b表中的数,把被29整除的去掉,剩下存放在数据a表中(当然存前需要清空数据,在第一步时一样,先清空数据b表),数据a与数据b来回互换,当筛选完后,判断筛选次数是奇数还是偶数,根据奇偶性,可以判断出那个表中的数据为最终结果,然后把结果抄写到素数表结果中即可,完成本次外循环,进入下一个外循环值,进行同样步骤。
如果还是不理解,可以针对性提问。
说起语文水平,我更是一般,只能是中下水平,语言表达,也是不到位,无法准确无误表达我的想法和思路,沟通起来有点费劲。
#10
xuminxz2021-09-14 09:32
最基本的问题我不明白。
楼主是向我们介绍一个程序吗?可没有看到啊。
是想让大家帮忙写个程序吗?可你不是已经有了吗?(结果都出来了呀。)
#11
laowan0012021-09-14 09:51
1.向大家介绍这个问题的解决思路
2.问大家你的解决思路是否可行
3.需要有人帮忙用程序实现你的解决方法
4.其他
不知楼主的意思是哪个
#12
独木星空2021-09-14 11:02
回复 10楼 xuminxz
大概流程是那样的。当然是想让大家安照这种方法方式编写一个vfp程序,以便优化,使程序运算时间大幅度降低。一个一个的筛太慢了,我等不及,想尽快获得结果,得到数据。
#13
独木星空2021-09-14 11:03
回复 11楼 laowan001
把1至3连起来就是我的意思。
#14
独木星空2021-09-14 12:13
CLEAR
SELECT 1
USE D:\vfp温习\素数式至17表.DBF ALIAS 素数式表
SELECT 2
USE D:\vfp温习\素数表万3.DBF ALIAS 素数表万3
SELECT 3
USE D:\vfp温习\素数表亿新.DBF ALIAS 素数表亿新 &&当时仅改变了别名,没有改原名,在素数表亿新后增加了198-200周期素数,改正,并去掉了后续素数
*INPUT "请输入预先值 K= " TO yxk
*INPUT "请输入步长值 bcz= " TO bcz
*INPUT "请输入初始值 csz= " TO csz
*INPUT "请输入外循环起始值 xks= " TO xks
*INPUT "请输入外循环终结值 zds= " TO zds
bcz=510510  &&从2乘到17,即素数17的素数阶乘
kssj=SECONDS()                      &&取出开始时间
FOR i=198 TO 200
@12,10 SAY i
            &&调了下顺序,原来在FOR j=1 TO 92160 的下边,执行第一个外循环,提示已经到了表尾
FOR j=1 TO 92160
SELECT 1
GO j
sss=素数式
bpz=sss+(i-1)*bcz               &&计算被判断值
Kf=INT(SQRT(bpz))                   &&求出被判断值的开方根
SELECT 2
GO 1
COUNT ALL FOR 素数<=kf TO jlh  &&借用原来的记录号,实际上统计kf以前的素数个数
  && jlh=RECNO()
SELECT 2   
GO 7                                &&从第二条记录开始读取素数(3)
FOR k=1 TO jlh-6                     &&内循环开始。这个循环实质上是从小到大顺序,依次读取素数。循环值是记录序号
qmz=MOD(bpz,素数)                   &&以读取的素数为条件,对被判断值求模
IF qmz=0 && OR qmz=2 OR qmz=6 OR qmz=8  如果符合这四个约定条件之一,就进行相应工作.如果一个也没有符合条件的,直接使记录指针向下移动一个(SKIP)
EXIT                                &&因为符合条件,则做完相应工作后跳出内循环
ENDIF
SKIP                                &&素数表指针向下移动一个
ENDFOR
IF k>jlh-6
SELECT 3               &&打开保存求解结果的信息表
APPEND BLANK                        &&增加一条空记录
REPLACE 素数 WITH bpz && 把bpz赋给素数        
ENDIF
ENDFOR
ENDFOR
=MESSAGEBOX("运行时间:"+LTRIM(STR(INT((SECONDS()-kssj)/60)))+"分"+LTRIM(STR(MOD(SECONDS()-kssj,60),5,2))+"秒",64,"运行时间提示")
这是一个制作素数表程序,也用到数据源表(素数式至17表→即用素数2,3,5,7,11,13,17这7个素数处理过的数据,每一层外循环数值增加值是510510(2*3*5*7*11*13*17),中层循环为92160(2*4*6*10*12*16),最;里层循环次数不定,有被判断值的开方值前素数个数确定最大循环次数,合数循环次数都小于最大循环次数,只有质数才是满循环),只不过,这个程序是一个一个的判断,排除,筛选。
而本帖要求一次性调入92160个数据(即中循环次数),在主要循环体中,是每次都得全部未完成,并不退出循环(循环次数以最大次数为准(不考虑那一批次中最小值的循环次数))。
一个程序是一个一个的处理,一个程序是一批一批的处理,这是问题的关键。(再就是处理过程中进行速度会加快,因为每循环一次被判断的数量只减不增)。
#15
laowan0012021-09-14 14:45
按你上面的程序执行后,最后的结果表的记录数是276480条吗?


[此贴子已经被作者于2021-9-14 15:00编辑过]

#16
laowan0012021-09-14 14:47
FOR i=198 TO 200
没明白为什么是198 TO 200,正常就是这样吗?
#17
独木星空2021-09-14 15:00
回复 16楼 laowan001
这是程序的最后一段计算数据,整个程序是从1开始的,那只运算了2个外循环,一次外循环可以处理510510自然数段内的92160个数值。运算结果不对。
#18
laowan0012021-09-14 15:05
能把你的正常程序和你的有关数据表发上来,并且正确结果的记录是多少能说一下吗?
既然想让大家帮你,那就请提供尽量多的信息

实话说,具体原理估计我是没理解清楚,但可以帮你优化程序

[此贴子已经被作者于2021-9-14 15:06编辑过]

#19
独木星空2021-09-14 15:12
回复 15楼 laowan001
那个数是需要处理的用数,里边有多少个素数找出来就可以了。不过,本问题不要用此程序,基本效仿把数排成一行或一列,然从素数3开始,划去其倍数,(奇数等差数列,不含1),继续划去5得倍数,一直这样划下去,直到最后一个素数倍划完为止,当然这个最后素数是本组数中最大的那个开方值前的最大素数。
#20
laowan0012021-09-14 15:22
既然不需要用程序,那就好
#21
吹水佬2021-09-14 15:28
先整好一个存放素数DBF,用时查表
#22
独木星空2021-09-14 15:33
回复 18楼 laowan001
所用到到的两个表已经压缩后,发在本主题中了,在三楼或四楼,原理简单,与单个筛选素数一致,只是本问题需要成批处理数据,就这点区别。我并没有编出程序,也没有结果,只是大概知道过程,一共涉及4个表,有一个表放素数(即运算结果),一个表放数据源(或者被处理数据,它是一个自然数段,经过了预处理,后续调用时,只需加周期9699690即可),数据a和数据b两个表是最内层用到的表,它们互相替换,直到完成最后一步筛查,把最终结果抄写到素数表结果中即可。奥,忘了,还有预先制的素数表,在最里层需要它做筛选条件,这样一共5表。
#23
skyingcat2021-09-14 15:37
嗯,好长
#24
独木星空2021-09-14 15:38
回复 20楼 laowan001
不是不需要用程序,而是不用我发到这个主题中的程序获得素数表。要用主题中的,从新设计一个程序来完成任务。
#25
独木星空2021-09-14 15:42
回复 21楼 吹水佬
关键是要用素数表,必须提前制作。就是用主题中的方法来制作素数表(我发了另一种制作素数表的程序,太慢了,无法满足要求)。
#26
吹水佬2021-09-14 16:43
回复 25楼 独木星空
是不是这样子
只有本站会员才能查看附件,请 登录

程序代码:
N = 100
DIMENSION arr[N,1]
arr = .T.
i = 2
DO WHILE i<=N
    FOR j=i+i TO N STEP i
        IF arr[j]
            arr[j] = .F.
        ENDIF
    ENDFOR
    j = i+1
    DO WHILE j<=N AND !arr[j]
        j = j+1
    ENDDO
    i = j
ENDDO
CREATE CURSOR tt (bol L, num I)
INSERT INTO tt FROM ARRAY arr
REPLACE ALL num WITH RECNO()
SELECT * FROM tt WHERE bol


[此贴子已经被作者于2021-9-14 16:52编辑过]

#27
独木星空2021-09-14 17:12
回复 26楼 吹水佬
是这种方式与处理结果。只不过这种没有分段,如果一次性处理一亿个数据,数组的长度有没有限制,即是没有限制,加大到10亿的数据量如何?最关键的是可能还大。所以必须改变一下,每次只处理一个固定周期内的数据,我给的数据源是9699690为周期的,里边有1658880个数据等待处理(一次性处理,不是一个一个的处理),每循环一个外循环值,数据源中的值加一个周期数9699690,进入第二个外循环,最里层的循环用mod(n,p)是否为0作为筛选条件(与其加它本身是一会事儿),在这个过程中,如果有被整除的就去掉了,不在进入下一个素数的排查之内。把最后一个待检验素数执行以后,判断最内层循环次数的奇偶性,找出那个是最终结果(数据a与数据b选其一,当然是正确的那个),把结果抄写到盛方素数的表中,此次外循环一次的数据处理完毕,进入第二轮即可。
#28
吹水佬2021-09-14 17:43
回复 27楼 独木星空
分段时,可用数组下标作为基址,加多个偏移量就可作为实际数据。
#29
吹水佬2021-09-14 19:17
以下是引用独木星空在2021-9-14 17:12:09的发言:

如果一次性处理一亿个数据,数组的长度有没有限制

反正是用DBF来存放,直接用DBF代替数组好了,DBF的记录号就当是数组的下标,但DBF也是有限。
#30
独木星空2021-09-14 20:00
现在编写出来个雏形,正在运行,看一看,运行结果如何,再发到网上,让大家提出宝贵意见,或者更好的优化方案。
#31
独木星空2021-09-14 20:44
CLEAR
SELECT 1
USE D:\标记法\数据源表.DBF ALIAS 数据源
SELECT 2
USE D:\标记法\素数表5万.DBF ALIAS 素数表参
SELECT 3
USE D:\标记法\数据表a.DBF ALIAS 数据a
SELECT 4
USE D:\标记法\数据表b.DBF ALIAS 数据b
SELECT 5
USE D:\标记法\素数表结果.DBF ALIAS 素数表果
                                  && bcz=510510  
kssj=SECONDS()                     
FOR i=1 TO 2
@12,10 SAY i
   SELECT 3
   DELETE ALL &&因为此表将写入新的数据,所以提前清空数据,即记录条值
   PACK
   SELECT 1
   GO 1
   FOR j=1 TO 1658880
   sss=素数式
   dclz=sss+(i-1)*9699690  &&dclz是待处理值
   SELECT 3
   APPEND BLANK
   REPLACE 数据1 WITH dclz
   SELECT 1
   SKIP
   ENDFOR
      SELECT 3
      GO 1658880
      bpz=数据1
      Kf=INT(SQRT(bpz))
      GO 1
      SELECT 2
      GO 1
      COUNT ALL FOR 素参<=kf TO jlh  && jlh=RECNO()
      xhcs=jlh-8 &&xhcs是循环次数的简写(第一个字母代替)
      SELECT 2   
      GO 9
      FOR k=1 TO xhcs
       sc=素参
        IF  MOD(k,2)=1
          SELECT 4
          DELETE ALL
          PACK
          SELECT 3
          jlts1=RECCOUNT()  &&把数据a表中的记录条总数赋给变量:jlts1
          GO 1
            for h1=1  to jlts1
            sj1=数据1
            ys1=MOD(sj1,sc)
            IF ys1=0
            ELSE
            SELECT 4
            APPEND BLANK
            REPLACE 数据2 WITH sj1
            ENDIF
            SELECT 3
            SKIP
            ENDFOR
         ELSE
           SELECT 3
           DELETE ALL
           PACK
           SELECT 4
           jlts2=RECCOUNT()  &&把数据b表中的记录条总数赋给变量:jlts2
            GO 1
            for h2=1  to jlts2
            sj2=数据2
            ys2=MOD(sj2,sc)
            IF ys2=0
            ELSE
            SELECT 3
            APPEND BLANK
            REPLACE 数据1 WITH sj2
            ENDIF
            SELECT 4
            SKIP
            ENDFOR
          ENDIF
       SELECT 2
       skip  
       ENDFOR
          IF MOD(xhcs,2)=1
          SELECT 4
          jlts3=RECCOUNT()
          GO 1
          for h3=1  to jlts3
           sj3=数据2
           SELECT 5
           APPEND BLANK
           REPLACE 素数 WITH sj3
           SELECT 4
           SKIP
          ENDFOR
          ELSE
          SELECT 3
          jlts4=RECCOUNT()
          GO 1
          for h4=1  to jlts4
           sj4=数据1
           SELECT 5
           APPEND BLANK
           REPLACE 素数 WITH sj4
           SELECT 3
           SKIP
          ENDFOR
          ENDIF
 ENDFOR
 =MESSAGEBOX("运行时间:"+LTRIM(STR(INT((SECONDS()-kssj)/60)))+"分"+LTRIM(STR(MOD(SECONDS()-kssj,60),5,2))+"秒",64,"运行时间提示")
这是我编写的程序,能正常运行,两周的运算时间为:29分40.24秒,在素数表结果中存储了1234399个数据,第一个1不是素数,第二个素数从3119开始的,3119前有443个素数,由1234399-1+443=1234841个素数,与以前方法制作的素数表中2*9699690=19399380内的素数个数一致,说明算法正确。
还是不满意运行时间,仍就偏大,不知道以前的方法运行时间是多少了(有空运行后再比对)。
#32
独木星空2021-09-14 21:35
运行第三第四周,用时42分48.07秒
#33
独木星空2021-09-14 22:08
CLEAR
SELECT 1
USE D:\vfp温习\素数式至19表.DBF ALIAS 素数式表
SELECT 2
USE D:\vfp温习\素数表万3.DBF ALIAS 素数表万3
SELECT 3
USE D:\vfp温习\素数表实验.DBF ALIAS 素数表 &&当时仅改变了别名,没有改原名,在素数表亿新后增加了198-200周期素数,改正,并去掉了后续素数
*INPUT "请输入预先值 K= " TO yxk
*INPUT "请输入步长值 bcz= " TO bcz
*INPUT "请输入初始值 csz= " TO csz
*INPUT "请输入外循环起始值 xks= " TO xks
*INPUT "请输入外循环终结值 zds= " TO zds
bcz=9699690 &&从2乘到17,即素数17的素数阶乘
kssj=SECONDS()                      &&取出开始时间
FOR i=1 TO 2
@12,10 SAY i
            &&调了下顺序,原来在FOR j=1 TO 92160 的下边,执行第一个外循环,提示已经到了表尾
FOR j=1 TO 1658880
@22,20 SAY j
SELECT 1
GO j
sss=素数式
bpz=sss+(i-1)*bcz               &&计算被判断值
Kf=INT(SQRT(bpz))                   &&求出被判断值的开方根
SELECT 2
GO 1
COUNT ALL FOR 素数<=kf TO jlh  &&借用原来的记录号,实际上统计kf以前的素数个数
  && jlh=RECNO()
SELECT 2   
GO 9                                &&从第二条记录开始读取素数(3)
FOR k=1 TO jlh-8                     &&内循环开始。这个循环实质上是从小到大顺序,依次读取素数。循环值是记录序号
qmz=MOD(bpz,素数)                   &&以读取的素数为条件,对被判断值求模
IF qmz=0 && OR qmz=2 OR qmz=6 OR qmz=8  如果符合这四个约定条件之一,就进行相应工作.如果一个也没有符合条件的,直接使记录指针向下移动一个(SKIP)
EXIT                                &&因为符合条件,则做完相应工作后跳出内循环
ENDIF
SKIP                                &&素数表指针向下移动一个
ENDFOR
IF k>jlh-8
SELECT 3               &&打开保存求解结果的信息表
APPEND BLANK                        &&增加一条空记录
REPLACE 素数 WITH bpz && 把bpz赋给素数        
ENDIF
ENDFOR
ENDFOR
=MESSAGEBOX("运行时间:"+LTRIM(STR(INT((SECONDS()-kssj)/60)))+"分"+LTRIM(STR(MOD(SECONDS()-kssj,60),5,2))+"秒",64,"运行时间提示")
一个一个的处理方法用时:65分41.26秒,明显比一个批次一个批次处理要慢的多。
#34
独木星空2021-09-15 06:03
希望大家提出优化建议。三楼有两个表,加上31楼的程序,就可以运行了。
#35
吹水佬2021-09-15 07:55
回复 34楼 独木星空
可否分享成品DBF文件
#36
独木星空2021-09-15 08:13
回复 35楼 吹水佬
所用到的表文件已经在3楼发出。程序也在31楼发出。您是要运行结果表文件吗?
#37
独木星空2021-09-15 08:27
回复 35楼 吹水佬
程序需要用到的五个表上传在这里(它们是自由表,已从数据库中导出,只是表明加了后缀---副表2字,其他未变动),程序在31楼,对应着稍微修改就可以用了。(路径及表名等信息)
只有本站会员才能查看附件,请 登录
只有本站会员才能查看附件,请 登录
只有本站会员才能查看附件,请 登录
只有本站会员才能查看附件,请 登录
只有本站会员才能查看附件,请 登录
#38
吹水佬2021-09-15 09:19
回复 37楼 独木星空
感谢分享
#39
独木星空2021-09-15 09:39
回复 18楼 laowan001
在31楼已经有了程序。另外在37楼所用表已经全部上传。静候您的佳音。
#40
laowan0012021-09-15 09:43
看到了

[此贴子已经被作者于2021-9-15 09:59编辑过]

#41
吹水佬2021-09-15 11:34
40000000以内耗时173s,破电脑就这速度。
用数组应该可以算到超过1亿内,每个数组中元素的最大数目 一般: 2G 字节、成员数组: 2G 字节
只有本站会员才能查看附件,请 登录

程序代码:
t = SECONDS()
N = 40000000
DIMENSION arr[N,1]
arr = .T.
i = 2
DO WHILE i<=N
    FOR j=i+i TO N STEP i
        arr[j] = .F.
    ENDFOR
    j = i+1
    DO WHILE j<=N AND !arr[j]
        j = j+1
    ENDDO
    i = j
ENDDO
CREATE CURSOR tt (bol L, num I)
INSERT INTO tt FROM ARRAY arr   
REPLACE ALL num WITH RECNO()
SELECT num FROM tt WHERE bol AND RECNO()>1 INTO TABLE 素数表
? SECONDS()-t  && N=20000000 - 87s, N=40000000 - 173s
#42
独木星空2021-09-15 13:04
回复 41楼 吹水佬
t=SECONDS()
N=20000000
DIMENSION arr[N,1]
arr=.T.
i=2
DO WHILE i<=N
    FOR j=i+i TO N STEP i
    arr[j]=.F.
    ENDFOR
    j=i+1
    DO WHILE j<=N AND !arr[j]
    j=j+1
    ENDDO
    i=j
 ENDDO
 CREATE CURSOR tt(bol L,num I)
 INSERT INTO tt FROM ARRAY arr
 REPLACE ALL num WITH RECNO()
 SELECT num FROM tt WHERE bol AND RECNO()>1 INTO TABLE 素数表
 ?SECONDS()-t &&N=20000000-38.754s ,N=40000000-78.142s
我按照您的程序手工抄录了一遍。用时较少,结果存盘到:C:\program files(X86)\vfp9\素数表.dbf 中了
#43
吹水佬2021-09-15 14:35
回复 42楼 独木星空
输出文件可以设置默认路径或指定路径
#44
mywisdom882021-09-15 15:33
回复 41楼 吹水佬
你这是什么算法,没看到你运算,就判断了。
#45
laowan0012021-09-15 15:39
* 改造了31楼的程序,结果表记录1234399,用时350秒
CLEAR
CLOSE DATABASES

LOCAL kkk

SELECT 1
USE 数据源.DBF ALIAS 数据源
SELECT 2
USE 素数表.DBF ALIAS 素数表参

SELECT 5
USE 素数结果.DBF ALIAS 素数表果
DELETE ALL
PACK

SELECT 素数 数据1 FROM 素数表果 WHERE 1=2 INTO CURSOR 数据a READWRITE

kssj = DATETIME()
FOR i=1 TO 2
    SELECT 素数式+(i-1)*9699690 数据1,CAST(1 as INT) 数据mod FROM 数据源 INTO CURSOR 数据a READWRITE

    SELECT 数据a
    GO BOTTOM     &&1658880
    Kf=INT(SQRT(数据1))

    SELECT 2
    kkk = 0
    SCAN FOR RECNO()>8 AND 素数<=kf
        IF RECNO()>kkk
            WAIT TRANSFORM(RECNO()) WINDOW NOWAIT NOCLEAR
            kkk = kkk + 10
        ENDIF
        
        UPDATE 数据a SET 数据mod=MOD(数据1,素数表参.素数) WHERE 数据mod>0

        SELECT 2
    ENDSCAN
   
    INSERT INTO 素数表果 (素数) SELECT 数据1 FROM 数据a WHERE 数据mod>0
   
 ENDFOR
 USE IN 数据a
 
 MESSAGEBOX( DATETIME()-kssj)
 SELECT 素数表果
 MESSAGEBOX( RECCOUNT())
 BROWSE
 
#46
laowan0012021-09-15 15:43
确实没看懂吹版的程序,好像没用到数据源表和素数表,明白的给说明一下下
#47
独木星空2021-09-15 16:08
回复 45楼 laowan001
首先多谢先生的回答。我还没有运行。那也比我原来的提速不少。
#48
独木星空2021-09-15 16:25
回复 46楼 laowan001
两楼都提到吹水佬算法问题,我有点喧宾夺主了,本不该回答的,只知道大概的意思,我把程序抄写到程序中,第一次运算结果出来后,竟然连素数表也没有找到,无奈之下运行了第二次,这是出现提示信息,说那个路径之下已经存在了,是否替换,这时我才找到存放素数表的路径。
扯多了,扯远了,回到正题,他的算法就像体育课老师让学生报数那样,从开头报数,报偶数者出列(第一个报的不出列),接着报3的倍数的出列,报5的倍数出列(当然他是把它们标记为假,false,开始都标记为真,true),这样直到小于等于N为止,然后把所有标记为真的存放到素数表中(当然第一条记录排除在外,它是1)

[此贴子已经被作者于2021-9-15 16:34编辑过]

#49
吹水佬2021-09-15 16:43
以下是引用mywisdom88在2021-9-15 15:33:14的发言:

你这是什么算法,没看到你运算,就判断了。

程序代码:
    筛选法求素数
    如:有10个数............ 234567891011
    先假设都是素数标记为1 .. 1111111111
    将不是素数的标记为0 .... 1101010001
    剩下标记为1的是素数 .... 23, ,5,, 7, , ,  ,11


DIMENSION arr[N,1]
arr = .T.
i = 2  筛选起始数
DO WHILE i<=N
    FOR j=i+i TO N STEP i  && 是自身倍数的不是素数
        arr[j] = .F.
    ENDFOR
    j = i+1
    DO WHILE j<=N AND !arr[j] && 跳过连续的非素数
        j = j+1
    ENDDO
    i = j  && 下次筛选的起始数
ENDDO
#50
吹水佬2021-09-15 16:48
回复 48楼 独木星空
用当前PRG文件路径作为默认路径,开头加几句:
CLEAR
SET TALK OFF
SET SAFETY OFF
CLOSE TABLES ALL
cDefPath = ADDBS(JUSTPATH(SYS(16)))
SET DEFAULT TO (cDefPath)
#51
独木星空2021-09-15 17:00
回复 46楼 laowan001
我的48楼答非所问。是我没有看懂各位的提问。多言了。吹水佬没有用到数据源(用不用素数表不重要,因为此主题的目的是要用到数据源,形成分段运算,更深层目的没有明说(计划改造后用到其他程序中去))。
1234