注册 登录
编程论坛 VFP论坛

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

独木星空 发布于 2021-09-13 21:47, 12492 次点击
标记法主题思路,标记法是把符合条件的标记为假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 回复
#52
独木星空2021-09-15 17:15
回复 45楼 laowan001
CLEAR
CLOSE DATABASES

LOCAL kkk

SELECT 1
USE D:\标记法\数据源表.DBF ALIAS 数据源
SELECT 2
USE D:\标记法\素数表5万.DBF ALIAS 素数表参

SELECT 5
USE D:\标记法\素数表结果1.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
我把程序复制,简单改了下(路径及字段名)。运算结果正确。用时610秒,看来电脑配置不行,运算有点慢。
#53
独木星空2021-09-15 17:50
回复 45楼 laowan001
用您的程序运算了3周和4周(每周跨度9699690,需要筛选1658880个数据)用时862秒(第一次的1,2周用时610可能不正确,因为那是运行中显示的数字?,这次运行时,它返回了一次,应该是每周的关联值,循环次数什么),素数个数(记录条数)1130040,与以前的素数表比对:19399380内(2周以内)1234841个,38798760内(4周以内)2364881个,差值1130040,与运算结果一致。
只是把原表已经覆盖,所以再次运行前,需要存放到一个不相干的表中。
#54
laowan0012021-09-15 19:26
回复 53楼 独木星空
运行时,屏幕右上角变化的数字是记录号,主要是感觉变化速率的
本次运行时间长度(秒)在运行结束时显示,同时显示结果表的记录数(用于核对)
#55
独木星空2021-09-15 19:58
回复 41楼 吹水佬
算到N=50000000时,用时95.805秒。不过,再大,提示内存不足,不能运行。
所以用分段法还是比较适用的,把i=i+i改为mod(N,i)=0,标记为假更为适用(可能会增加时间),所用i=j变为从参照素数表中的下一个素数为好(skip),运算到本批次最大数开方值即可。
总起来说,用数据源表,参照素数表,盛放素数的表,这三个表用到了,就可以形成分段计算,用mod(N,P)=0作为标记假的条件。
那个程序以N前素数做为步长和筛选条件,每步不涉及其他非倍数的记录条(或者数组的下标),直到不大于N为止。
后种方法是每步都需要检查每一个数(可以绕开前组已经标记过的),但是它只需要到开方值即可。
吹水佬版主能不能把那个程序改成用数据源和参照素数表的程序,以便分段运算。(深层用意是把它嫁接到别的程序里去,那样的数组,及处理方式(指标记为假的条件)无法嫁接到其他程序里去)。
#56
吹水佬2021-09-15 20:57
回复 55楼 独木星空
要算多少个素数
按字节(BYTE)算有限
按位(BIT)算也有限
DBF存放顶多也就10亿个
VFP按文件算也就2G
#57
吹水佬2021-09-15 21:07
建一个素数表不用太计较速度了吧,建好就不动的。
逐个数去判断,是素数就保存起来,分段算也简单。
#58
独木星空2021-09-15 21:23
回复 45楼 laowan001
CLEAR
SELECT 1
USE D:\标记法\数据源表.DBF ALIAS 数据源
SELECT 2
USE D:\标记法\素数表5万.DBF ALIAS 素数表参
SELECT 3
USE D:\标记法\数据表a.DBF ALIAS 数据a
SELECT 5
USE D:\标记法\素数表结果.DBF ALIAS 素数表果
kssj=SECONDS()                     
FOR i=7 TO 8
   @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=素参
            SELECT 3
            jlts1=RECCOUNT()  &&把数据a表中的记录条总数赋给变量:jlts1
            GO 1
            FOR h1=1  to jlts1
            sj1=数据1
            ys1=MOD(sj1,sc)
            IF ys1=0
            SELECT 3
            DELETE next 1
            ENDIF
            SELECT 3
            SKIP
            ENDFOR
            SELECT 3
            PACK
        SELECT 2
        skip  
        ENDFOR
      
            SELECT 3
            jlts2=RECCOUNT()  &&把数据a表中的记录条总数赋给变量:jlts1
            GO 1
            FOR h2=1  to jlts2
            sj2=数据1
            SELECT 5
            APPEND BLANK
            REPLACE 素数 WITH sj2
            SELECT 3
            SKIP
            ENDFOR
 ENDFOR
 =MESSAGEBOX("运行时间:"+LTRIM(STR(INT((SECONDS()-kssj)/60)))+"分"+LTRIM(STR(MOD(SECONDS()-kssj,60),5,2))+"秒",64,"运行时间提示")
在您的提示下,对我原来的做了修改(主循环体),用时25分7.25秒,比不上先生的,不知道那里浪费了时间,记录条数:1076003.
#59
laowan0012021-09-15 23:01
  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 素数式+(i-1)*9699690 数据1 FROM 数据源 INTO CURSOR 数据a READWRITE

使用cursor在内存里运行,磁盘交互少,速度会快些
上面两种方法你可以单独比较一下

另外,循环里做表的pack,效率也会降低,何况你是一个大记录数的表,虽然pack会减少记录数,看似会减少运行时间,但表需要重新整理,相当于读出来再写回去,得不偿失

对表中记录的遍历,可使用scan/endscan,用for/endfor,每次还要skip,相当于分解动作

向一个表插入记录,建议使用insert into ,比append blank+replace 要强


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

#60
独木星空2021-09-16 05:27
回复 59楼 laowan001
看来时间是浪费在读取数据和写入数据上了。如果不把数据放在表中,而是直接在内存中处理的话,把数据源中的数值加9699690*(i-1)直接调入内存(如何用数组代替它们),不读取不写入表,直接在内存变量中完成筛选工作如何处理?(在内存中,把那些余数是0的都做标记(就像吹水佬那样,调入一批数据(一个外循环值)后,先标记为真,然后开始把整除的标记为假,最后把还是真的存表),这样能不能实现,因为吹水佬的是一次性程序,无法重复操作(即分段运算))。
#61
独木星空2021-09-16 05:47
回复 57楼 吹水佬
是不用太计较速度。建立一个10亿内的素数表,一个一个的处理起来,得大概运算一个月的时间,当然建起了,可以拿来用。可是在没有建起前,又有几个人能等待的了。所以能建立分段运算是关键,把任务划分,分段运算,一次性运算无论是内存,还是运行时间都不允许。所以,从vfp表的大小,和内存的大小来考虑都不允许一次性的运算模式,10亿内有5千万多素数,vfp表可以存放,但是10亿,不用10亿,1亿就无法运行了,提示内存不足,所以还是分段计算为好,还有一个有利条件,可以同时打开4个程序运行(再多也不行,因为此时8GB内存几乎全部占用)。总起来说,不如分段运算,有更多的可操作性。
我所设计的,速度慢,关键就是数据的存储,读取上浪费了时间,能不能把一个外循环批次的数据用数组调入内存,然后对内存变量进行处理,意即调入是都为真,然后开始调入参考素数表中的素数,对它们进行从新设置,把整除的标记为假,处理完毕。把还是真的存盘,完成本次操作,进入下一个外循环即可。
#62
schtg2021-09-16 05:50
向各位大侠学习,谢谢分享!
吹版的运行确实很快的
只有本站会员才能查看附件,请 登录


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

#63
独木星空2021-09-16 06:28
回复 62楼 schtg
说明你的电脑配置更高。我的运行80多。
#64
mywisdom882021-09-16 08:44
以下是引用独木星空在2021-9-15 19:58:10的发言:

算到N=50000000时,用时95.805秒。不过,再大,提示内存不足,不能运行。
所以用分段法还是比较适用的,把i=i+i改为mod(N,i)=0,标记为假更为适用(可能会增加时间),所用i=j变为从参照素数表中的下一个素数为好(skip),运算到本批次最大数开方值即可。
总起来说,用数据源表,参照素数表,盛放素数的表,这三个表用到了,就可以形成分段计算,用mod(N,P)=0作为标记假的条件。
那个程序以N前素数做为步长和筛选条件,每步不涉及其他非倍数的记录条(或者数组的下标),直到不大于N为止。
后种方法是每步都需要检查每一个数(可以绕开前组已经标记过的),但是它只需要到开方值即可。
吹水佬版主能不能把那个程序改成用数据源和参照素数表的程序,以便分段运算。(深层用意是把它嫁接到别的程序里去,那样的数组,及处理方式(指标记为假的条件)无法嫁接到其他程序里去)。

用吹斑竹的方法,为了避免数据很大的时候,出现问题,采取分段处理就可以了。
比如你要处理10亿个,你分成10段,每段就变成1亿了。
#65
独木星空2021-09-16 08:45
回复 59楼 laowan001
CLEAR
SELECT 1
USE D:\标记法\数据源表.DBF ALIAS 数据源
SELECT 2
USE D:\标记法\素数表5万.DBF ALIAS 素数表参
SELECT 3
USE D:\标记法\数据表a.DBF ALIAS 数据a
SELECT 5
USE D:\标记法\素数表结果.DBF ALIAS 素数表果
kssj=SECONDS()                     
FOR i=11 TO 12
   @12,10 SAY i
      SELECT 素数式+(i-1)*9699690 数据1 FROM 数据源 INTO CURSOR 数据a READWRITE
      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=素参
            SELECT 3
            jlts1=RECCOUNT()  &&把数据a表中的记录条总数赋给变量:jlts1
            GO 1
            FOR h1=1  to jlts1
            sj1=数据1
            ys1=MOD(sj1,sc)
            IF ys1=0
            SELECT 3
            DELETE next 1
            ENDIF
            SELECT 3
            SKIP
            ENDFOR
            SELECT 3
            PACK
        SELECT 2
        skip  
        ENDFOR
      
            SELECT 3
            jlts2=RECCOUNT()  &&把数据a表中的记录条总数赋给变量:jlts1
            GO 1
            FOR h2=1  to jlts2
            sj2=数据1
            SELECT 5
            APPEND BLANK
            REPLACE 素数 WITH sj2
            SELECT 3
            SKIP
            ENDFOR
 ENDFOR
 =MESSAGEBOX("运行时间:"+LTRIM(STR(INT((SECONDS()-kssj)/60)))+"分"+LTRIM(STR(MOD(SECONDS()-kssj,60),5,2))+"秒",64,"运行时间提示")
把开始部分改写后,运行后提示信息:对话框标题:程序错误,内容:别名已被使用;后来把“数据源”用数字1代替,“数据a”用数字3代替;这时运行后:提示信息:SQL:找不到列"素数式"(是用单文本号括着,我打不出来)。
#66
mywisdom882021-09-16 08:47
做成1个过程来调用,开始数,结束数,这样分段处理
#67
独木星空2021-09-16 08:52
回复 64楼 mywisdom88
问题的关键是不能分段。那种算法只能从1开始排列下标(数组的)。
#68
独木星空2021-09-16 09:07
回复 66楼 mywisdom88
对!需要把标记为假的条件,改成从参照素数表中调入的素数整倍数为假(或者余数为0的为假),也不在运算到N前,只需要到每批次的开方值前即可(回到一个一个的处理算法上,不过这里有区别,只考虑每批最大值的开方值即可,不在考虑其他的数值,再就是,原先是一个被筛选值把它开方值前的素数要用一遍(当然不是所有的是这样,只有被筛选值是素数才行,合数中间就跳出循环了);后者是一个素数把这一批数筛除一遍,接着下一个素数再把剩余的(没有被标记为假的)筛除一遍,....,一直进行下去,直到最后一个符合条件的素数参与为止)。
所以分段法,需要改变条件(标记为假的条件),这时也要用到参照素数表,和分段数据源这些表。
#69
吹水佬2021-09-16 09:21
以下是引用独木星空在2021-9-16 05:47:09的发言:

是不用太计较速度。建立一个10亿内的素数表,一个一个的处理起来,得大概运算一个月的时间,当然建起了,可以拿来用。可是在没有建起前,又有几个人能等待的了。

不清楚你这个素数表的实际使用情况,具体操作可能有不同的方法。
如果是对一个随机的数用查表法进行判断是不是素数,程序可以设计成自动维护这个素数表,不用先创建好这个素数表。当这个程序查表次数过程越来越多,这个素数表的数据记录就越多,程序查找素数的速度就越接近查表法的速度。

#70
laowan0012021-09-16 09:21
回复 65楼 独木星空
程序最开始加一句
close database
就不会出“别名已被使用”了

找不到列,可能有两种原因:(1)工作区不对(2)字段名不对
#71
吹水佬2021-09-16 09:29
以下是引用独木星空在2021-9-16 05:47:09的发言:

所以能建立分段运算是关键,把任务划分,分段运算,一次性运算无论是内存,还是运行时间都不允许。

用那种方法应该都可以分次、分段进行,只是算法不同。

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

#72
吹水佬2021-09-16 09:42
以下是引用独木星空在2021-9-16 05:47:09的发言:

还有一个有利条件,可以同时打开4个程序运行(再多也不行,因为此时8GB内存几乎全部占用)。

用多进程分配任务来处理是可以,进程间协同处理同一个表数据。能同时打开进程的个数应该不只4个,VFP的进程占内存不算多,通常就几M,顶多也就10几M。至于DBF文件处理是通过缓冲与磁盘交换来处理,占实际内存也不会太多。
#73
吹水佬2021-09-16 10:13
以下是引用独木星空在2021-9-16 05:47:09的发言:

我所设计的,速度慢,关键就是数据的存储,读取上浪费了时间,能不能把一个外循环批次的数据用数组调入内存,然后对内存变量进行处理,意即调入是都为真,然后开始调入参考素数表中的素数,对它们进行从新设置,把整除的标记为假,处理完毕。把还是真的存盘,完成本次操作,进入下一个外循环即可。

用数组分块处理好再将数组整块写入表速度肯定比逐个数据直接读写表快。
另外,算法也很重要,如:
Kf=INT(SQRT(bpz))                   &&求出被判断值的开方根
SELECT 2
GO 1
COUNT ALL FOR 素数<=kf TO jlh  &&借用原来的记录号,实际上统计kf以前的素数个数

素数<=kf 即 素数<=INT(SQRT(bpz))
开方运算应该比乘方运行慢,尤其是数值较大时更慢,可试改为:
(素数*素数)<=bpz
另,在循环体内尽量避免使用扫描整个表的语句,如:
COUNT ALL FOR 素数<=kf TO jlh  &&借用原来的记录号,实际上统计kf以前的素数个数
这样当表记录越来越多时,运行速度就越慢,尤其是循环次数多时更慢。


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

#74
独木星空2021-09-16 10:22
回复 59楼 laowan001
select 列名 from 表名

用那句代替后,不是提示表别名已被占用,就是找不到列"素数式"
不知道为何?
#75
独木星空2021-09-16 10:27
回复 70楼 laowan001
能想到的也就这两种情况。
#76
独木星空2021-09-16 12:42
回复 45楼 laowan001
CLEAR
SELECT 1
USE D:\标记法\数据源表.DBF ALIAS 数据源
SELECT 2
USE D:\标记法\素数表5万.DBF ALIAS 素数表参
SELECT 3
USE D:\标记法\数据表a.DBF ALIAS 数据a
SELECT 5
USE D:\标记法\素数表结果1.DBF ALIAS 素数表果
kssj=SECONDS()                     
FOR i=11 TO 12
   @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=素参
            SELECT 3
            jlts1=RECCOUNT()  &&把数据a表中的记录条总数赋给变量:jlts1
            GO 1
            FOR h1=1  to jlts1
            sj1=数据1
            ys1=MOD(sj1,sc)
            IF ys1=0
            SELECT 3
            DELETE next 1
            ENDIF
            SELECT 3
            SKIP
            ENDFOR
            SELECT 3
            PACK
        SELECT 2
        skip  
        ENDFOR
      
       INSERT INTO 素数表果 (素数) SELECT 数据1 FROM 数据a
 ENDFOR
 =MESSAGEBOX("运行时间:"+LTRIM(STR(INT((SECONDS()-kssj)/60)))+"分"+LTRIM(STR(MOD(SECONDS()-kssj,60),5,2))+"秒",64,"运行时间提示")   计算11,12两个区间用时27分58:53秒
这次只是把存表部分改动了一下(即程序最后部分),开始部分没有修改成功,不是别名被占用,就是找不到列“素数式”(英文符号单引号)。
主要循环体还没有用数组代替在内存中运算(或许这是提速的关键)。
#77
laowan0012021-09-16 13:42
回复 76楼 独木星空
最开始加上  close database
#78
独木星空2021-09-16 15:41
回复 59楼 laowan001
SELECT 素数式+(i-1)*9699690 数据1 FROM 数据源 INTO CURSOR 数据a READWRITE
用此语句代替后,一直也不能正常运行(包括关闭数据,无论放到什么位置),不是提示别名被占用,就是找不到列“素数式”,后来还出现其他对话框(定位表文件,选择定位数据源不正确,选择定位数据a不正确,二者应选其一,那个也不正确)。
最后把别名改成了表原名,可以了,不再有其他提示,不过第一步就说超出记录范围,干脆把go 1658880去掉,直接用i*9699690代替最大开方值,只进行了一步,go 1也超出记录范围,啊?,数据a里边没有任何记录条。
所以我怀疑那条语句并没有把数据源中的值+(i-1)*9699690后改写到数据a中。
#79
laowan0012021-09-16 15:52
use 数据源
brow
看下有没有字段:素数式,如果没有的话,或者改表中的字段名,或者改你的程序
这种基本错误应该会排查了

程序开始估计还是没加 close database,否则不会出现“别名被占用”
#80
独木星空2021-09-16 16:04
回复 59楼 laowan001
CLEAR
close database
SELECT 1
USE D:\标记法\数据源表.DBF ALIAS 数据源A
SELECT 2
USE D:\标记法\素数表5万.DBF ALIAS 素数表参
SELECT 3
USE D:\标记法\数据表a.DBF ALIAS 数据A
SELECT 5
USE D:\标记法\素数表结果.DBF ALIAS 素数表果
kssj=SECONDS()                     
FOR i=11 TO 12
   @12,10 SAY i
       SELECT 3
       DELETE ALL &&因为此表将写入新的数据,所以提前清空数据,即记录条值
       PACK
      INSERT INTO 数据A (数据1) SELECT 素数式+(i-1)*9699690 FROM 数据源A && 素数式+(i-1)*9699690 数据1 FROM  数据源表 INTO CURSOR 数据表a READWRITE  &&select list item 选择列表项,之前它不管,[ ,...]应该是字段名用逗号隔开
      SELECT 3
      bpz=i*9699690
      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=素参
            SELECT 3
            jlts1=RECCOUNT()  &&把数据a表中的记录条总数赋给变量:jlts1
            GO 1
            FOR h1=1  to jlts1
            sj1=数据1
            ys1=MOD(sj1,sc)
            IF ys1=0
            SELECT 3
            DELETE next 1
            ENDIF
            SELECT 3
            SKIP
            ENDFOR
            SELECT 3
            PACK
        SELECT 2
        skip  
        ENDFOR
      
            SELECT 3
            jlts2=RECCOUNT()  &&把数据a表中的记录条总数赋给变量:jlts1
            GO 1
            FOR h2=1  to jlts2
            sj2=数据1
            SELECT 5
            APPEND BLANK
            REPLACE 素数 WITH sj2
            SELECT 3
            SKIP
            ENDFOR
 ENDFOR
 =MESSAGEBOX("运行时间:"+LTRIM(STR(INT((SECONDS()-kssj)/60)))+"分"+LTRIM(STR(MOD(SECONDS()-kssj,60),5,2))+"秒",64,"运行时间提示")
那个语句无法应用,把那部分用最后的语句,改写了下,能正常运行,用时28分27:93秒,也不知道时间是否减少了。
#81
独木星空2021-09-16 16:07
所以主要是把主循环体的算法改进才可以,用数组代替,直接调入内存,不来回读取和存入等操作,最后一次性把还是真的存表即可。
#82
laowan0012021-09-16 16:14
45楼给你的程序,运行时间已经在10分钟以里了,不知为什么还非要用你原来的程序。你这个程序的写法,运行效率也不会有大的改善

程序主循环体中的处理我已经试过使用数组方式了,运行时间差不多,所以没在这里提供
#83
独木星空2021-09-16 18:56
回复 82楼 laowan001
放上来最好,供大家欣赏。我是想练习各种方法方式,比对它们的用时(说效率更贴切)。
再就是吹水佬的运算速度最快,但是没有用数据源和素数表,没有分成段落,无法移植到类似程序中去,计划移植程序中是排除两种余数以上,而不是单单是一个余数0,获得的是k生素数的一个代表值。
#84
独木星空2021-09-16 19:06
CLEAR
CLOSE DATABASES

LOCAL kkk

SELECT 1
USE d:\标记法\素数式17.DBF ALIAS 素数式17
SELECT 2
USE d:\标记法\素数表参考.DBF ALIAS 素数表参
SELECT 3
USE d:\标记法\三生素数.DBF ALIAS 三素表
DELETE ALL
PACK

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

kssj = DATETIME()
FOR i=9901 TO 9905
    SELECT 式17+(i-1)*510510 数据1,CAST(1 as INT) 数据mod FROM 素数式17 INTO CURSOR 数据a READWRITE

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

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

        SELECT 2
    ENDSCAN
   
    INSERT INTO 三素表 (三素) SELECT 数据1 FROM 数据a WHERE 数据mod<>0 and 数据mod<>4 and 数据mod<>6
   
 ENDFOR
 USE IN 数据a
 
 MESSAGEBOX( DATETIME()-kssj)
这是简单改写了,用于求最密三生素数的程序,循环5个外循环值用时69秒(开始条件用错,条件是用or连接的,结果一个也没有筛除出去,全部留下了,进入多少,出来多少,一个也没有去掉,而且用时222秒,后来把连接条件的改为and(并且))。
#85
独木星空2021-09-16 19:17
CLEAR
CLOSE DATABASES
SELECT 1
USE d:\标记法\素数式17.DBF ALIAS 素数式17
SELECT 2
USE d:\标记法\素数表参考.DBF ALIAS 素数表参
SELECT 3
USE d:\标记法\三生素数.DBF ALIAS 三素表
DELETE ALL
PACK

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

kssj = DATETIME()
FOR i=9906 TO 9910
@12,10 SAY i
    SELECT 式17+(i-1)*510510 数据1,CAST(1 as INT) 数据mod FROM 素数式17 INTO CURSOR 数据a READWRITE

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

    SELECT 2
    kkk = 0
    SCAN FOR RECNO()>7 AND 素数<=kf
        
        UPDATE 数据a SET 数据mod=MOD(数据1,素数表参.素数) WHERE 数据mod<>0 and 数据mod<>4 and 数据mod<>6

        SELECT 2
    ENDSCAN
   
    INSERT INTO 三素表 (三素) SELECT 数据1 FROM 数据a WHERE 数据mod<>0 and 数据mod<>4 and 数据mod<>6
   
 ENDFOR
 USE IN 数据a
 
 MESSAGEBOX( DATETIME()-kssj)
去了显示记录条值(或者说是主体循环的循环次数),加了显示外循环值(即处理第几批次的值)。
#86
独木星空2021-09-16 20:06
CLEAR
CLOSE DATABASES
SELECT 1
USE d:\标记法\素数式至19.DBF ALIAS 素数式19
SELECT 2
USE d:\标记法\素数表参考.DBF ALIAS 素数表参
SELECT 3
USE d:\标记法\三生素数新.DBF ALIAS 三素表
DELETE ALL
PACK

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

kssj = DATETIME()
FOR i=703 TO 705
@12,10 SAY i
    SELECT 式19+(i-1)*9699690 数据1,CAST(1 as INT) 数据mod FROM 素数式19 INTO CURSOR 数据a READWRITE

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

    SELECT 2
   
    SCAN FOR RECNO()>8 AND 素数<=kf
        
        UPDATE 数据a SET 数据mod=MOD(数据1,素数表参.素数) WHERE 数据mod<>0 and 数据mod<>4 and 数据mod<>6

        SELECT 2
    ENDSCAN
   
    INSERT INTO 三素表 (三素) SELECT 数据1 FROM 数据a WHERE 数据mod<>0 and 数据mod<>4 and 数据mod<>6
   
 ENDFOR
 USE IN 数据a
 
 MESSAGEBOX( DATETIME()-kssj)
进一步升级,到了一步跨过9699690个自然数段,循环3次外循环,相当于上贴19*3=57个外循环,用时740秒,节省时间20多秒,不算多。
#87
吹水佬2021-09-16 23:15
VFP写这个东东效率相对较低,简单写个DLL给VFP调用好象好点。
只有本站会员才能查看附件,请 登录

程序代码:
cDefPath = ADDBS(JUSTPATH(SYS(16)))
SET DEFAULT TO (cDefPath)
DECLARE LONG CreatePrime IN Prime LONG,LONG,STRING@
t = SECONDS()
CreatePrime(1, 10000000, cDefPath+"Prime1.txt")
? SECONDS()-t  && 8s
t = SECONDS()
CreatePrime(10000001, 40000000, cDefPath+"Prime2.txt")
? SECONDS()-t  && 49s
#88
schtg2021-09-17 06:17
回复 87楼 吹水佬
吹版,这个很好,可分段,且很快哦!
只有本站会员才能查看附件,请 登录
#89
独木星空2021-09-17 07:31
回复 87楼 吹水佬
下载了,还没有应用。谢谢吹水佬版主!
#90
laowan0012021-09-17 08:12
吹版真牛,佩服!!!
#91
mywisdom882021-09-17 09:07
用87楼的,1亿个,用55秒。。。
生成1个54.2 MB的文件
#92
独木星空2021-09-17 19:16
回复 87楼 吹水佬
cDefPath = ADDBS(JUSTPATH(SYS(16)))
SET DEFAULT TO (cDefPath)
DECLARE LONG CreatePrime IN Prime LONG,LONG,STRING@
t = SECONDS()
CreatePrime(1, 10000000, cDefPath+"Prime1.txt")
? SECONDS()-t  && 7.953s 文本文件prime1 5.61MB
t = SECONDS()
CreatePrime(10000001, 40000000, cDefPath+"Prime2.txt")
? SECONDS()-t  && 50.209s  文本文件prime2  16.8MB
这次在电脑上运行时间与吹水佬版主的相当,再次谢谢吹水佬版主!
#93
独木星空2021-09-17 19:42
回复 87楼 吹水佬
cDefPath = ADDBS(JUSTPATH(SYS(16)))
SET DEFAULT TO (cDefPath)
DECLARE LONG CreatePrime IN Prime LONG,LONG,STRING@
t = SECONDS()
CreatePrime(40000001, 70000000, cDefPath+"Prime3.txt")
? SECONDS()-t  && 72.825s Prime3 16.0MB
t = SECONDS()
CreatePrime(70000001, 100000000, cDefPath+"Prime4.txt")
? SECONDS()-t  && 89.604s Prime4 15.6MB
分段计算了两部分,用时都较少。
吹水佬版主
#94
独木星空2021-09-18 09:12
回复 82楼 laowan001
希望得到共享。把用数组的方法代替主循环体(不在用数据a和数据b两个表)。
#95
wengjl2021-09-18 13:18
谢谢分享!

[此贴子已经被作者于2021-9-18 13:30编辑过]

#96
独木星空2021-09-19 18:09
回复 87楼 吹水佬
cDefPath = ADDBS(JUSTPATH(SYS(16)))
SET DEFAULT TO (cDefPath)
DECLARE LONG CreatePrime IN Prime LONG,LONG,STRING@
t = SECONDS()
CreatePrime(2000000001, 2040000000, cDefPath+"Prime68.txt")
? SECONDS()-t  && 72.825s Prime3 16.0MB
t = SECONDS()
CreatePrime(2040000001, 2070000000, cDefPath+"Prime69.txt")
? SECONDS()-t  && 89.604s Prime4 15.6MB
t = SECONDS()
CreatePrime(2070000001, 2100000000, cDefPath+"Prime70.txt")
? SECONDS()-t  && 72.825s Prime3 16.0MB
t = SECONDS()
CreatePrime(2100000001, 2130000000, cDefPath+"Prime71.txt")
? SECONDS()-t  && 89.604s Prime4 15.6MB
t = SECONDS()
CreatePrime(2130000001, 2160000000, cDefPath+"Prime72.txt")
? SECONDS()-t  && 72.825s Prime3 16.0MB
t = SECONDS()
CreatePrime(2160000001, 2190000000, cDefPath+"Prime73.txt")
? SECONDS()-t  && 89.604s Prime4 15.6MB
t = SECONDS()
CreatePrime(2190000001, 2220000000, cDefPath+"Prime74.txt")
? SECONDS()-t  && 72.825s Prime3 16.0MB
t = SECONDS()
CreatePrime(2220000001, 2250000000, cDefPath+"Prime75.txt")
? SECONDS()-t  && 89.604s Prime4 15.6MB
t = SECONDS()
CreatePrime(2250000001, 2280000000, cDefPath+"Prime76.txt")
? SECONDS()-t  && 72.825s Prime3 16.0MB
t = SECONDS()
CreatePrime(2280000001, 2310000000, cDefPath+"Prime77.txt")
? SECONDS()-t  && 89.604s Prime4 15.6MB
t = SECONDS()
CreatePrime(2310000001, 2340000000, cDefPath+"Prime78.txt")
? SECONDS()-t  && 89.604s Prime4 15.6MB
计算到"Prime72.txt"时出错,前多半部为正数,截止2147483647;随后变成了负数,-2147483637(紧接着它的绝对值变小),到后来的表的数值绝对值一直减小,大有往回返的程度。因为突然停电,不知何种原因造成,"Prime76.txt"已有,只有后两个没有运算完,没有存储。

[此贴子已经被作者于2021-9-19 18:11编辑过]

#97
吹水佬2021-09-19 20:21
回复 96楼 独木星空
VFP整数是有符号的
整数的最小值 -2,147,483,647
整数的最大值 2,147,483,647
我试改改那个DLL直接返回无符号,VFP就不用转换。
#98
吹水佬2021-09-19 22:04
回复 97楼 吹水佬
输出无符号整数
只有本站会员才能查看附件,请 登录

只能算到最大素数0xFFFFFFEF
CreatePrime(0xFFFFFFE1, 0xFFFFFFFF, cDefPath+"Prime1.txt")
#99
独木星空2021-09-20 10:48
回复 98楼 吹水佬
谢谢!吹水佬版主。试运行了一下,由于突然停电,只保存一个文件,打开看了一下,是正整数(素数)。
#100
独木星空2021-09-21 09:34
回复 98楼 吹水佬
在中秋佳节之日,再次谢谢吹版主的辛勤劳作!
#101
独木星空2021-09-21 19:41
回复 98楼 吹水佬
cDefPath = ADDBS(JUSTPATH(SYS(16)))
SET DEFAULT TO (cDefPath)
DECLARE LONG CreatePrime IN Prime LONG,LONG,STRING@
t = SECONDS()
CreatePrime(4280000001,4310000001,cDefPath+"Prime143.txt")
? SECONDS()-t
t = SECONDS()
CreatePrime(4310000001,4340000001,cDefPath+"Prime144.txt")
? SECONDS()-t
"Prime142.txt "时还没有出错,因为它的最大值是4280000000,而整数限制2147483647*2=4294967294,还小于它。
而到"Prime143.txt "时就出错了,运行时间0.008秒,文件为空白,即没有存数据;
"Prime144.txt "时运行时间123.583秒,文件存储的数据都是8位数(千万级别)。

只能算到最大素数0xFFFFFFEF?它是不是整数溢出(即最大整数值),我对它不太了解,我以为是9999999999,十位数最大值。
1234