数学中国

 找回密码
 注册
搜索
热搜: 活动 交友 discuz
楼主: 白新岭

[原创]请教vfbpgyfk先生一个编程问题

  [复制链接]
 楼主| 发表于 2021-9-13 21:10 | 显示全部楼层
标记法主题思路,标记法是把符合条件的标记为假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,即一次性可以判断这样的自然数段。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-9-13 21:16 | 显示全部楼层
最原始的筛法,一个一个的去判断,筛除,也就是都在重复同一项工作,效率低下;而这种算法是一次性调入一个批次的数据(这个批次是一个自然数段落,一个递增周期),是众数,不是一个一个的来,而是一同进入,然后第一次就排除了,最多的数据(因为小素数先参与排查,根据几率均等原则,它的倍数最多)。
回复 支持 反对

使用道具 举报

发表于 2021-9-14 20:47 | 显示全部楼层
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,"运行时间提示")
回复 支持 反对

使用道具 举报

发表于 2021-9-14 20:48 | 显示全部楼层
上边是一种新的算法制作素数表程序。
回复 支持 反对

使用道具 举报

发表于 2021-9-15 15:34 | 显示全部楼层
select [all|distinct ] [top nexpr [percent]] select_list_item [,...]
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-9-15 20:52 | 显示全部楼层
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 中了
这是vfp论坛吹水佬的程序,运行速度快,缺点不能计算更大数据(大数据内存不足),不能分段运算。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-9-15 20:56 | 显示全部楼层
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秒,看来电脑配置不行,运算有点慢。
这是vfp论坛laowan001的程序,能分段,运算速度比一个一个的筛选素数快。
没有缺陷,但是我没有弄清他的算法,好像是把余数为0的剔除,只留下(或者只抄写余数大于0的数据)。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-9-15 21:00 | 显示全部楼层
843#的现在已经改写了,主要循环体改成了delete next 1(即谁被整除就删除谁),全部标记完后,一起彻底删除pack,在进入下一个素数,进行同样的工作。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-9-15 21:26 | 显示全部楼层
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,"运行时间提示")
主循环体用了标记删除及彻底删除,不在用数据a与数据b互换。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-9-15 22:07 | 显示全部楼层
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=9 TO 10
   @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,"运行时间提示")
这段用时26分29.31秒
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|小黑屋|数学中国 ( 京ICP备05040119号 )

GMT+8, 2025-5-19 22:53 , Processed in 0.087493 second(s), 15 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表