看到有人实现了一个计算质数的函数,就是效率有点差,贴一个以前写的计算质数的算法。

目标很简单,列出100以内的质数。

其实算法很简单,两个循环就搞定了。但是发现使用不同的算法,执行效率差别之大相当惊人,特别是数据量级很大的时候。

下面就是最常见的一种写法:(也是最差的一种)

[PHP]

SQL> SET SERVEROUT ON

SQL> DECLARE

2   V_FLAG BOOLEAN;

3  BEGIN

4   FOR I IN 2 .. 100 LOOP

5    V_FLAG := TRUE;

6    FOR J IN 2 .. I - 1 LOOP

7     IF  MOD(I,J) = 0 THEN

8      V_FLAG := FALSE;

9     END IF;

10    END LOOP;

11

12    IF V_FLAG = TRUE THEN

13     DBMS_OUTPUT.PUT_LINE(I);

14    END IF;

15   END LOOP;

16  END;

17  /

2

3

5

7

11

13

17

19

23

29

31

37

41

43

47

53

59

61

67

71

73

79

83

89

97

PL/SQL 过程已成功完成。

已用时间:  00: 00: 00.09

.

[/PHP]

由于屏幕输出操作比较慢,为了避免影响,将屏幕输出关闭。并将数据量增大到100000,以下所有的测试都在这个相同条件下进行。

[PHP]

SQL> DECLARE

2   V_FLAG BOOLEAN;

3  BEGIN

4   FOR I IN 2 .. 100000 LOOP

5    V_FLAG := TRUE;

6    FOR J IN 2 .. I - 1 LOOP

7     IF  MOD(I,J) = 0 THEN

8      V_FLAG := FALSE;

9     END IF;

10    END LOOP;

11

12    IF V_FLAG = TRUE THEN

13     --DBMS_OUTPUT.PUT_LINE(I);

14     NULL;

15    END IF;

16   END LOOP;

17  END;

18  /

PL/SQL 过程已成功完成。

已用时间:  02: 02: 58.73

.

[/PHP]

这种方法在100000数据量的用时居然达到了2个小时。

如果稍微仔细考虑一下,就会发现,系统做了很多没有必要的工作,首先判断是否能整除的时候不需要循环到I – 1,只要执行到I的平方根就可以了,而且,如果I可以被整除就不需要继续循环,可以马上跳出内层循环了。经过简单优化后:

[PHP]

SQL> DECLARE

2   V_FLAG BOOLEAN;

3  BEGIN

4   FOR I IN 2 .. 100000 LOOP

5    V_FLAG := TRUE;

6    FOR J IN 2 .. TRUNC(POWER(I, 0.5)) LOOP

7     IF  MOD(I,J) = 0 THEN

8      V_FLAG := FALSE;

9      EXIT;

10     END IF;

11    END LOOP;

12

13    IF V_FLAG = TRUE THEN

14     --DBMS_OUTPUT.PUT_LINE(I);

15     NULL;

16    END IF;

17   END LOOP;

18  END;

19  /

PL/SQL 过程已成功完成。

已用时间:  00: 00: 16.21

.

[/PHP]

效果十分的明显,从2个多小时,缩减到了16秒。

算法还可以进一步优化,考虑到质数中只有2是偶数,其他都是奇数,可以将2单独处理,然后将循环的步长设置为2,这样外层循环次数就减少了一半。

[PHP]

SQL> DECLARE

2   I NUMBER DEFAULT 3;

3   V_FLAG BOOLEAN;

4  BEGIN

5   --DBMS_OUTPUT.PUT_LINE(2);

6   WHILE I < 100000 LOOP

7    V_FLAG := TRUE;

8    FOR J IN 2 .. TRUNC(POWER(I, 0.5)) LOOP

9     IF  MOD(I,J) = 0 THEN

10      V_FLAG := FALSE;

11      EXIT;

12     END IF;

13    END LOOP;

14

15    IF V_FLAG = TRUE THEN

16     --DBMS_OUTPUT.PUT_LINE(I);

17     NULL;

18    END IF;

19   I := I + 2;

20   END LOOP;

21  END;

22  /

PL/SQL 过程已成功完成。

已用时间:  00: 00: 09.37

.

[/PHP]

仔细考虑一下,其实用来被整除的数是质数就足够了,不需要对所有奇数进行判断。在下面的过程中,使用索引表来保存计算得到的所有的质数:

[PHP]

SQL> DECLARE

2   TYPE T_RECORD IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;

3   V_RESULT T_RECORD;

4   V_FLAG BOOLEAN;

5   V_CNT NUMBER;

6   I NUMBER DEFAULT 3;

7  BEGIN

8   V_RESULT(1) := 2;

9   --DBMS_OUTPUT.PUT_LINE(V_RESULT(1));

10   WHILE(I < 100000) LOOP

11    V_FLAG := TRUE;

12    V_CNT := V_RESULT.COUNT;

13    FOR J IN 1..V_CNT LOOP

14     IF V_RESULT(J) > POWER(I, 0.5) THEN

15      EXIT;

16     END IF;

17     IF MOD(I,V_RESULT(J)) = 0 THEN

18      V_FLAG := FALSE;

19      EXIT;

20     END IF;

21    END LOOP;

22    IF V_FLAG THEN

23    -- DBMS_OUTPUT.PUT_LINE(I);

24     V_RESULT(V_CNT+1) := I;

25    END IF;

26    I := I + 2;

27   END LOOP;

28  END;

29  /

PL/SQL 过程已成功完成。

已用时间:  00: 00: 06.68

.

[/PHP]

已经将速度提高到了6秒左右,还能不能更快呢?注意到在最内层循环中调用了一个函数POWER(I, 0.5),下面将这个表达式转换一下,避免使用这个函数:

[PHP]

SQL> DECLARE

2   TYPE T_RECORD IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;

3   V_RESULT T_RECORD;

4   V_FLAG BOOLEAN;

5   I NUMBER DEFAULT 3;

6  BEGIN

7   --DBMS_OUTPUT.PUT_LINE(2);

8   V_RESULT(1) := 2;

9   WHILE(I < 100000) LOOP

10    V_FLAG := TRUE;

11    FOR J IN 1..V_RESULT.COUNT LOOP

12     IF V_RESULT(J) * V_RESULT(J) > I THEN

13      EXIT;

14     END IF;

15     IF MOD(I,V_RESULT(J)) = 0 THEN

16      V_FLAG := FALSE;

17      EXIT;

18     END IF;

19    END LOOP;

20    IF V_FLAG THEN

21    -- DBMS_OUTPUT.PUT_LINE(I);

22     V_RESULT(V_RESULT.COUNT + 1) := I;

23    END IF;

24    I := I + 2;

25   END LOOP;

26  END;

27  /

PL/SQL 过程已成功完成。

已用时间:  00: 00: 01.03

.

[/PHP]

难以置信吧,一个执行两个小时的PL/SQL,通过算法的调整可以优化到了1秒。

其实能优化的地方还有很多,不过这些优化能带来的性能提升已经很小了。比如:

[PHP]

SQL> DECLARE

2   TYPE T_RECORD IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;

3   V_RESULT T_RECORD;

4   V_FLAG BOOLEAN;

5   I NUMBER DEFAULT 3;

6  BEGIN

7   --DBMS_OUTPUT.PUT_LINE(2);

8   V_RESULT(0) := 2;

9   WHILE(I < 100000) LOOP

10    V_FLAG := TRUE;

11    FOR J IN 1..V_RESULT.COUNT - 1 LOOP

12     IF V_RESULT(J) * V_RESULT(J) > I THEN

13      EXIT;

14     END IF;

15     IF MOD(I,V_RESULT(J)) = 0 THEN

16      V_FLAG := FALSE;

17      EXIT;

18     END IF;

19    END LOOP;

20    IF V_FLAG THEN

21    -- DBMS_OUTPUT.PUT_LINE(I);

22     V_RESULT(V_RESULT.COUNT) := I;

23    END IF;

24    I := I + 2;

25   END LOOP;

26  END;

27  /

PL/SQL 过程已成功完成。

已用时间:  00: 00: 00.96

.

[/PHP]

由于从3开始步长为2,因此判断随后的质数的时候,没有必要用2去整除,而直接可以从3开始。

过程仍然可以进一步优化,可以省略掉不必要的赋值和判断语句:

[PHP]

SQL> DECLARE

2   TYPE T_RECORD IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;

3   V_RESULT T_RECORD;

4   I NUMBER DEFAULT 3;

5  BEGIN

6   --DBMS_OUTPUT.PUT_LINE(2);

7   V_RESULT(1) := 3;

8   WHILE(I < 100000) LOOP

9    FOR J IN 1..V_RESULT.COUNT LOOP

10     IF MOD(I,V_RESULT(J)) = 0 THEN

11      EXIT;

12     END IF;

13     IF V_RESULT(J) * V_RESULT(J) > I THEN

14     -- DBMS_OUTPUT.PUT_LINE(I);

15      V_RESULT(V_RESULT.COUNT + 1) := I;

16      EXIT;

17     END IF;

18    END LOOP;

19    I := I + 2;

20   END LOOP;

21   V_RESULT(0) := 2;

22  END;

23  /

PL/SQL 过程已成功完成。

已用时间:  00: 00: 00.96

.

[/PHP]

但是在100000这个数量级已经看不出性能的差别了。正如Tom所说的,系统总是可以提高1%的性能,不过付出的代价会越来越大。

刚才测试发现,将MOD函数转换一下,性能还会有一个相对明显的提升

[PHP]

SQL> DECLARE

2   TYPE T_RECORD IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;

3   V_RESULT T_RECORD;

4   I NUMBER DEFAULT 3;

5  BEGIN

6   --DBMS_OUTPUT.PUT_LINE(2);

7   V_RESULT(1) := 3;

8   WHILE(I < 100000) LOOP

9    FOR J IN 1..V_RESULT.COUNT LOOP

10     IF V_RESULT(J) * V_RESULT(J) > I THEN

11      --DBMS_OUTPUT.PUT_LINE(I);

12      V_RESULT(V_RESULT.COUNT + 1) := I;

13      EXIT;

14     END IF;

15     IF TRUNC(I/V_RESULT(J)) = I/V_RESULT(J) THEN

16      EXIT;

17     END IF;

18    END LOOP;

19    I := I + 2;

20   END LOOP;

21   V_RESULT(0) := 2;

22  END;

23  /

PL/SQL 过程已成功完成。

已用时间:  00: 00: 00.87

.

[/PHP]

再来一次尝试:

[PHP]

SQL> DECLARE

2   TYPE T_RECORD IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;

3   V_RESULT T_RECORD;

4   I NUMBER DEFAULT 3;

5   N NUMBER DEFAULT 0;

6  BEGIN

7   --DBMS_OUTPUT.PUT_LINE(2);

8   V_RESULT(1) := 3;

9   WHILE(I < 100000) LOOP

10    FOR J IN 1..V_RESULT.COUNT LOOP

11     IF V_RESULT(J) * V_RESULT(J) > I THEN

12      --DBMS_OUTPUT.PUT_LINE(I);

13      V_RESULT(V_RESULT.COUNT + 1) := I;

14      EXIT;

15     END IF;

16     IF TRUNC(I/V_RESULT(J)) = I/V_RESULT(J) THEN

17      EXIT;

18     END IF;

19    END LOOP;

20    IF N = 2 THEN

21     I := I + 4;

22     N := 1;

23    ELSE

24     I := I + 2;

25     N := N + 1;

26    END IF;

27   END LOOP;

28   V_RESULT(0) := 2;

29  END;

30  /

PL/SQL 过程已成功完成。

已用时间:  00: 00: 00.84

.

[/PHP]

看来Tom说的确实没有错,优化的方法总是存在的。

原文出自:http://space.itpub.net/4227/viewspace-68767

如何用mysql求质数_PLSQL计算质数相关推荐

  1. python调用函数来判断质数_Python计算-质数的判断

    python 如何判断一个数是不是质数 让这个数除,从2开始到她的一半,如果余数没有0就是质数.大兄弟,这是非常基本的算法,你都拿到网上问. 欢迎来到夜影驱动编程的. import math def ...

  2. 计算100以内最大质数和求100以内的质数

    #计算100以内最大质数 for n in range(100,1,-1):#如果n==2时则最大质数为2if n==2:print('100以内最大质数为2')#判断是否为偶数if n%2==0:c ...

  3. php100以内质数求和,100以内的质数_PHP质数计算三种方法 php求100以内的质数

    摘要 腾兴网为您分享:PHP质数计算三种方法 php求100以内的质数,自动刷宝,长沙银行,猿辅导,愈加等软件知识,以及cf一键刷枪,业主名录采集软件,卡乐光电,魔方虚拟光驱,掌上徐州,卡农社区,fa ...

  4. 利用数组求前n个质数

    我的算法思想和实现方式都在代码和注释当中呢,这样的方式确实使算法复杂度降低一个等级,很好啊. #include <stdio.h> #include <time.h>/*** ...

  5. JAVA打印出1到100的所有质数,并计算共有多少个质数。

    JAVA打印出1–100的所有质数,并计算共有多少个质数. 首先我们要知道什么是质数? 质数又称为质数,是指一个大于1的自然数,除了他本身和1外不能被其他数所整除的数. 1.如何用java判断输入的数 ...

  6. 计算质数通过分区(Partition)提高Spark的运行性能(转载+自己理解)

    这篇博客是对[1]的进一步详细描述 自己的配置是台式机一台+笔记本组成spark集群 #-------------------------------------------------------- ...

  7. c语言 do while 素数,c语言题目:用while语句求2000以内所有质数(素数)

    c语言题目:用while语句求2000以内所有质数(素数) 关注:100  答案:3  手机版 解决时间 2021-02-26 06:59 提问者祗剩寂寞 2021-02-25 10:11 小弟初学, ...

  8. PL/SQL计算质数

     PL/SQL计算质数 2008-01-08 10:48:31|  分类: 默认分类 |  标签: |举报 |字号大中小 订阅 看到别人写的一片计算质数文章, 感觉不错:转过来学习一下. 目标很简 ...

  9. java求小于n的素数_java_Java实现求小于n的质数的3种方法,质数概念 质数,又称素数, - phpStudy...

    Java实现求小于n的质数的3种方法 质数概念 质数,又称素数,指在一个大于1的自然数中,除了1和此整数自身外,无法被其他自然数整除的数(也可定义为只有1和本身两个因数的数). 最小的素数是2,也是素 ...

最新文章

  1. 16Adapter(适配器)模式
  2. es6总结(一) ——开发环境
  3. 设计模式之 抽象工厂 封装业务逻辑层和Dao层
  4. apache 版本_Apache Hudi 0.5.1版本重磅发布
  5. ElementUI中的el-table中实现动态添加一行、删除一行、清空所有行
  6. Swift之深入解析可选链的功能和使用
  7. linux开发板推荐_【新品发布】WiFi开发板XW-01-Kit,超低功耗,冷启快联,智能门锁首选!...
  8. 使用Maven原型高效创建Eclipse模块
  9. 25. 合并两个排序的链表
  10. python中str是什么_Python中str字符串的功能介绍
  11. 点个外卖时间,我把「软中断」搞懂了
  12. hibernate5(8)操纵对象入门[3]操控对象封装方法
  13. 【VS开发】ConvertBSTRToString(filename) 不能将string转换为BSTR
  14. 多重背包单调队列优化思路_单调队列优化多重背包问题
  15. python模拟账号登录_用Python(Tornado)模拟登录小米帐号
  16. Qt调用工业相机之映美精相机
  17. ios gif的分解和展示
  18. 什么是磁盘?磁盘的组成?接口和分区?
  19. 实现回到顶部功能的三种方法
  20. 上传图片计算机没有桌面,电脑桌面消失了!

热门文章

  1. Android 手机设置 Charles 代理,pem 证书安装不上?
  2. 基于深度学习的中文语音识别系统框架搭建
  3. micropython复现经典单片机项目(一)旋转立方块
  4. 怎样制作gif格式动图?如何在线自制gif动图?
  5. jmonkeyEngineSDK安装部署及IDEA集成JME3开发
  6. js日期计算,根据当前日期计算n个月后的日期
  7. 客户心声 | 四川省人社厅杨玉成一行充分肯定桂溪街道劳动保障工作信息化建设平台
  8. 手机开机启动慢是什么原因_手机开机慢,详细教您手机开机慢怎么办
  9. 洞悉数字资产存储与交易 免于“韭菜”的命运
  10. php执行who命令,Linux_在Linux系统中使用who和whoami命令获取用户信息,who用法:who [选项]... [ 文件 | - phpStudy...