标题:用删除法编写一个制作素数表的vfp程序
只看楼主
独木星空
Rank: 16Rank: 16Rank: 16Rank: 16
来 自:河北省曲阳县
等 级:版主
威 望:57
帖 子:713
专家分:556
注 册:2016-6-29
得分:0 
回复 46楼 laowan001
我的48楼答非所问。是我没有看懂各位的提问。多言了。吹水佬没有用到数据源(用不用素数表不重要,因为此主题的目的是要用到数据源,形成分段运算,更深层目的没有明说(计划改造后用到其他程序中去))。

素数问题的解决是我学习编程永恒的动力。
2021-09-15 17:00
独木星空
Rank: 16Rank: 16Rank: 16Rank: 16
来 自:河北省曲阳县
等 级:版主
威 望:57
帖 子:713
专家分:556
注 册:2016-6-29
得分:0 
回复 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秒,看来电脑配置不行,运算有点慢。

素数问题的解决是我学习编程永恒的动力。
2021-09-15 17:15
独木星空
Rank: 16Rank: 16Rank: 16Rank: 16
来 自:河北省曲阳县
等 级:版主
威 望:57
帖 子:713
专家分:556
注 册:2016-6-29
得分:0 
回复 45楼 laowan001
用您的程序运算了3周和4周(每周跨度9699690,需要筛选1658880个数据)用时862秒(第一次的1,2周用时610可能不正确,因为那是运行中显示的数字?,这次运行时,它返回了一次,应该是每周的关联值,循环次数什么),素数个数(记录条数)1130040,与以前的素数表比对:19399380内(2周以内)1234841个,38798760内(4周以内)2364881个,差值1130040,与运算结果一致。
只是把原表已经覆盖,所以再次运行前,需要存放到一个不相干的表中。

素数问题的解决是我学习编程永恒的动力。
2021-09-15 17:50
laowan001
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:54
帖 子:802
专家分:1914
注 册:2015-12-30
得分:0 
回复 53楼 独木星空
运行时,屏幕右上角变化的数字是记录号,主要是感觉变化速率的
本次运行时间长度(秒)在运行结束时显示,同时显示结果表的记录数(用于核对)
2021-09-15 19:26
独木星空
Rank: 16Rank: 16Rank: 16Rank: 16
来 自:河北省曲阳县
等 级:版主
威 望:57
帖 子:713
专家分:556
注 册:2016-6-29
得分:0 
回复 41楼 吹水佬
算到N=50000000时,用时95.805秒。不过,再大,提示内存不足,不能运行。
所以用分段法还是比较适用的,把i=i+i改为mod(N,i)=0,标记为假更为适用(可能会增加时间),所用i=j变为从参照素数表中的下一个素数为好(skip),运算到本批次最大数开方值即可。
总起来说,用数据源表,参照素数表,盛放素数的表,这三个表用到了,就可以形成分段计算,用mod(N,P)=0作为标记假的条件。
那个程序以N前素数做为步长和筛选条件,每步不涉及其他非倍数的记录条(或者数组的下标),直到不大于N为止。
后种方法是每步都需要检查每一个数(可以绕开前组已经标记过的),但是它只需要到开方值即可。
吹水佬版主能不能把那个程序改成用数据源和参照素数表的程序,以便分段运算。(深层用意是把它嫁接到别的程序里去,那样的数组,及处理方式(指标记为假的条件)无法嫁接到其他程序里去)。

素数问题的解决是我学习编程永恒的动力。
2021-09-15 19:58
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:432
帖 子:10064
专家分:41463
注 册:2014-5-20
得分:0 
回复 55楼 独木星空
要算多少个素数
按字节(BYTE)算有限
按位(BIT)算也有限
DBF存放顶多也就10亿个
VFP按文件算也就2G
2021-09-15 20:57
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:432
帖 子:10064
专家分:41463
注 册:2014-5-20
得分:0 
建一个素数表不用太计较速度了吧,建好就不动的。
逐个数去判断,是素数就保存起来,分段算也简单。
2021-09-15 21:07
独木星空
Rank: 16Rank: 16Rank: 16Rank: 16
来 自:河北省曲阳县
等 级:版主
威 望:57
帖 子:713
专家分:556
注 册:2016-6-29
得分:0 
回复 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.

素数问题的解决是我学习编程永恒的动力。
2021-09-15 21:23
laowan001
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:54
帖 子:802
专家分:1914
注 册:2015-12-30
得分:0 
  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编辑过]

2021-09-15 23:01
独木星空
Rank: 16Rank: 16Rank: 16Rank: 16
来 自:河北省曲阳县
等 级:版主
威 望:57
帖 子:713
专家分:556
注 册:2016-6-29
得分:0 
回复 59楼 laowan001
看来时间是浪费在读取数据和写入数据上了。如果不把数据放在表中,而是直接在内存中处理的话,把数据源中的数值加9699690*(i-1)直接调入内存(如何用数组代替它们),不读取不写入表,直接在内存变量中完成筛选工作如何处理?(在内存中,把那些余数是0的都做标记(就像吹水佬那样,调入一批数据(一个外循环值)后,先标记为真,然后开始把整除的标记为假,最后把还是真的存表),这样能不能实现,因为吹水佬的是一次性程序,无法重复操作(即分段运算))。

素数问题的解决是我学习编程永恒的动力。
2021-09-16 05:27



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




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

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