楼主: tree_new_bee

递归with真是个好东西

[复制链接]
论坛徽章:
10
CTO参与奖
日期:2009-02-20 09:44:20ITPUB年度最佳技术原创精华奖
日期:2013-03-22 13:18:30迷宫蛋
日期:2012-05-07 10:55:58茶鸡蛋
日期:2012-04-19 16:08:262012新春纪念徽章
日期:2012-01-04 11:54:462011新春纪念徽章
日期:2011-01-04 10:24:02数据库板块每日发贴之星
日期:2010-12-19 01:01:02数据库板块每日发贴之星
日期:2010-12-13 01:01:012009日食纪念
日期:2009-07-22 09:30:00优秀写手
日期:2014-02-08 06:00:12
31#
 楼主| 发表于 2010-12-12 17:31 | 只看该作者
太疯狂了。

不过,看进度条似乎明天就能出来了, 只是不知进度条准不准。

使用道具 举报

回复
论坛徽章:
407
紫蛋头
日期:2012-05-21 10:19:41迷宫蛋
日期:2012-06-06 16:02:49奥运会纪念徽章:足球
日期:2012-06-29 15:30:06奥运会纪念徽章:排球
日期:2012-07-10 21:24:24鲜花蛋
日期:2012-07-16 15:24:59奥运会纪念徽章:拳击
日期:2012-08-07 10:54:50奥运会纪念徽章:羽毛球
日期:2012-08-21 15:55:33奥运会纪念徽章:蹦床
日期:2012-08-21 21:09:51奥运会纪念徽章:篮球
日期:2012-08-24 10:29:11奥运会纪念徽章:体操
日期:2012-09-07 16:40:00
32#
发表于 2010-12-12 18:47 | 只看该作者
原帖由 tree_new_bee 于 2010-12-12 17:31 发表
太疯狂了。

不过,看进度条似乎明天就能出来了, 只是不知进度条准不准。

plsql求10,20~1E7的最大公约数

SQL> declare
  2  a number;
  3  b number;
  4  tmp number;
  5  gcd number;
  6  begin
  7  b:=10;
  8  for i in 2..1E6 loop
  9  a:=i*10;
10  b:=case i when 2 then b else gcd end;
11  while a<>0 loop
12  tmp:=a;
13  a:=mod(b,a);
14  b:=tmp;
15  end loop;
16  gcd:=b;
17  end loop;
18  dbms_output.put_line(gcd);
19  end;
20  /
10

PL/SQL 过程已成功完成。

已用时间:  00: 00: 02.02

使用道具 举报

回复
论坛徽章:
10
CTO参与奖
日期:2009-02-20 09:44:20ITPUB年度最佳技术原创精华奖
日期:2013-03-22 13:18:30迷宫蛋
日期:2012-05-07 10:55:58茶鸡蛋
日期:2012-04-19 16:08:262012新春纪念徽章
日期:2012-01-04 11:54:462011新春纪念徽章
日期:2011-01-04 10:24:02数据库板块每日发贴之星
日期:2010-12-19 01:01:02数据库板块每日发贴之星
日期:2010-12-13 01:01:012009日食纪念
日期:2009-07-22 09:30:00优秀写手
日期:2014-02-08 06:00:12
33#
 楼主| 发表于 2010-12-12 19:21 | 只看该作者
原帖由 〇〇 于 2010-12-12 18:47 发表

plsql求10,20~1E7的最大公约数



PLSQL容易微调一些。

上面的代码,调整一下顺序,尽量让每次都是大数mod小数, 可以节省一半的mod操作。

declare
  a   number;
  b   number;
  tmp number;
  gcd number;
begin
  b := 20;
  for i in 2 .. 1E6 loop
    a := i * 10;
    --b := case i when 2 then b else gcd end;
    while b <> 0 loop
      tmp := b;
      b   := mod(a, b);
      a   := tmp;
    end loop;
    b:=a;
  end loop;
  dbms_output.put_line(b);
end;

改过后, 在我这里从1.9s, 降到0.7s

使用道具 举报

回复
论坛徽章:
484
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02ITPUB北京九华山庄2008年会纪念徽章
日期:2008-01-21 16:50:24ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452010新春纪念徽章
日期:2010-03-01 11:04:552010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010系统架构师大会纪念
日期:2010-09-04 13:35:54ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512011新春纪念徽章
日期:2011-02-18 11:43:32ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:54
34#
发表于 2010-12-12 22:48 | 只看该作者
原帖由 tree_new_bee 于 10-12-10 13:05 发表

什么叫射一下?


流氓兔的流氓招数

使用道具 举报

回复
论坛徽章:
407
紫蛋头
日期:2012-05-21 10:19:41迷宫蛋
日期:2012-06-06 16:02:49奥运会纪念徽章:足球
日期:2012-06-29 15:30:06奥运会纪念徽章:排球
日期:2012-07-10 21:24:24鲜花蛋
日期:2012-07-16 15:24:59奥运会纪念徽章:拳击
日期:2012-08-07 10:54:50奥运会纪念徽章:羽毛球
日期:2012-08-21 15:55:33奥运会纪念徽章:蹦床
日期:2012-08-21 21:09:51奥运会纪念徽章:篮球
日期:2012-08-24 10:29:11奥运会纪念徽章:体操
日期:2012-09-07 16:40:00
35#
发表于 2010-12-13 07:33 | 只看该作者
原帖由 tree_new_bee 于 2010-12-12 17:31 发表
太疯狂了。

不过,看进度条似乎明天就能出来了, 只是不知进度条准不准。

出来了

SQL> with t as (
  2  select level*10 n from dual connect by level<=1E6)
  3  ,t1 as (select n n1, lead(n ,1) over (order by n desc) n2 from t )
  4  ,t2 as (select max(n1) n1, max(n2)n2  from t1 )
  5  , mgcd(a,b, a2, b2) as
  6  (select n1, n2, n1, n2 from t2
  7  union all
  8  select
  9  case when b2=0 then (select max(n) from t where n<a) else a end,
10  case when b2=0 then a2 else b end,
11  case when b2=0 then (select max(n) from t where n<a) else b2 end,
12  case when b2=0 then  a2 else mod(a2, b2) end
13  from mgcd where a is not null
14  )
15  cycle a,b,a2,b2 set iscycle to 'y' default 'n'
16  select min(a2) from mgcd where b2=0
17
SQL> /

   MIN(A2)
----------
        10

已用时间:  59: 31: 03.74

使用道具 举报

回复
论坛徽章:
407
紫蛋头
日期:2012-05-21 10:19:41迷宫蛋
日期:2012-06-06 16:02:49奥运会纪念徽章:足球
日期:2012-06-29 15:30:06奥运会纪念徽章:排球
日期:2012-07-10 21:24:24鲜花蛋
日期:2012-07-16 15:24:59奥运会纪念徽章:拳击
日期:2012-08-07 10:54:50奥运会纪念徽章:羽毛球
日期:2012-08-21 15:55:33奥运会纪念徽章:蹦床
日期:2012-08-21 21:09:51奥运会纪念徽章:篮球
日期:2012-08-24 10:29:11奥运会纪念徽章:体操
日期:2012-09-07 16:40:00
36#
发表于 2010-12-13 07:46 | 只看该作者
原帖由 tree_new_bee 于 2010-12-12 17:31 发表
太疯狂了。

不过,看进度条似乎明天就能出来了, 只是不知进度条准不准。

怎么看出来的?

使用道具 举报

回复
论坛徽章:
10
CTO参与奖
日期:2009-02-20 09:44:20ITPUB年度最佳技术原创精华奖
日期:2013-03-22 13:18:30迷宫蛋
日期:2012-05-07 10:55:58茶鸡蛋
日期:2012-04-19 16:08:262012新春纪念徽章
日期:2012-01-04 11:54:462011新春纪念徽章
日期:2011-01-04 10:24:02数据库板块每日发贴之星
日期:2010-12-19 01:01:02数据库板块每日发贴之星
日期:2010-12-13 01:01:012009日食纪念
日期:2009-07-22 09:30:00优秀写手
日期:2014-02-08 06:00:12
37#
 楼主| 发表于 2010-12-13 08:59 | 只看该作者
原帖由 〇〇 于 2010-12-13 07:46 发表

怎么看出来的?



这个需要很很internel的oracle知识和高深的数学知识才能做到了:

进度条当时显示的大约为满格的3/4左右, 而当时运行了2天, 所以剩余时间大概要半天左右。


使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
38#
发表于 2010-12-14 00:00 | 只看该作者
原帖由 〇〇 于 2010-12-12 13:43 发表
newkid的gcd
SQL> WITH n AS (
  2  select level*10 n from dual connect by level  


我的写法每一步都会和集合n做连接,如果n很大, 效率就成问题。NB哥的好一些因为他只是在b2=0才会执行一个子查询。
如果集合是很有规律的,那么只要在递归的每一步生成新数据就行了,集合n没有必要:
WITH t (id,a,b,gcd) AS (
  SELECT 10,0,1,10 FROM DUAL
  UNION ALL
  SELECT DECODE(t.a,0,t.id+10,t.id)
        ,DECODE(t.a,0,t.id+10,MOD(t.b,t.a))
        ,DECODE(t.a,0,t.gcd,t.a)
        ,DECODE(mod(t.b,t.a),0,t.a,t.gcd)
    FROM t
   WHERE (t.id<1E5 OR t.id=1E5 AND t.a<>0)
)
SELECT gcd FROM t WHERE a=0 AND id=1E5;


       GCD
----------
        10

Elapsed: 00:00:00.45


如果集合n不能省略,最好的办法就是把它变成hash表放在内存里直接访问,可惜ORACLE的递归WITH没有这高级功能。
改用MODEL, 引用效率高了,但是没办法精确控制迭代次数,不得不先构造一个笛卡尔积。
SELECT b
   FROM (SELECT *
           FROM (SELECT ROWNUM n
                       ,ROWNUM*10 val ---- 用另外的列存放要求公倍数的值。不一定是连续的自然数
                   FROM DUAL
                 CONNECT BY ROWNUM<=1e4)
               ,(SELECT ROWNUM col
                   FROM DUAL
                CONNECT BY ROWNUM<=30 ---- 假设辗转相除法迭代次数不超过30
                )
         MODEL IGNORE NAV RETURN UPDATED ROWS
         DIMENSION BY (n,col)
         MEASURES (val,0 a,val b)
         RULES AUTOMATIC ORDER (
                a[n>1,any] order by n,col = CASE WHEN cv(col)=1 THEN val[cv(),cv()]
                                                 WHEN a[cv(),cv()-1]<>0 THEN MOD(b[cv(),cv()-1],a[cv(),cv()-1])
                                                 ELSE 0
                                            END
               ,b[n>1,any] order by n,col = CASE WHEN cv(col)=1 THEN b[cv()-1,30]
                                                 WHEN a[cv(),cv()-1]<>0 THEN a[cv(),cv()-1]
                                                 ELSE b[cv(),cv()-1]
                                            END
                )
         )
WHERE n=1E4 and col=30;

         B
----------
        10

Elapsed: 00:00:11.73

使用道具 举报

回复
论坛徽章:
407
紫蛋头
日期:2012-05-21 10:19:41迷宫蛋
日期:2012-06-06 16:02:49奥运会纪念徽章:足球
日期:2012-06-29 15:30:06奥运会纪念徽章:排球
日期:2012-07-10 21:24:24鲜花蛋
日期:2012-07-16 15:24:59奥运会纪念徽章:拳击
日期:2012-08-07 10:54:50奥运会纪念徽章:羽毛球
日期:2012-08-21 15:55:33奥运会纪念徽章:蹦床
日期:2012-08-21 21:09:51奥运会纪念徽章:篮球
日期:2012-08-24 10:29:11奥运会纪念徽章:体操
日期:2012-09-07 16:40:00
39#
发表于 2010-12-14 06:48 | 只看该作者

回复 #38 newkid 的帖子

nice

使用道具 举报

回复
论坛徽章:
10
CTO参与奖
日期:2009-02-20 09:44:20ITPUB年度最佳技术原创精华奖
日期:2013-03-22 13:18:30迷宫蛋
日期:2012-05-07 10:55:58茶鸡蛋
日期:2012-04-19 16:08:262012新春纪念徽章
日期:2012-01-04 11:54:462011新春纪念徽章
日期:2011-01-04 10:24:02数据库板块每日发贴之星
日期:2010-12-19 01:01:02数据库板块每日发贴之星
日期:2010-12-13 01:01:012009日食纪念
日期:2009-07-22 09:30:00优秀写手
日期:2014-02-08 06:00:12
40#
 楼主| 发表于 2010-12-14 14:24 | 只看该作者
看OO的2^1000的帖子:  http://www.itpub.net/viewthread. ... ;page=1#pid13982681
用递归做了两个任意大数相乘:


with t0 as (select
'1234567' arg1,
'87654321' arg2
from dual)
,t1 as (select rownum pos, substr(arg1, -rownum, 1) d from t0 connect by rownum<=length(arg1))
,t2 as (select 2 id , rownum pos, substr(arg2, -rownum, 1) d from t0 connect by rownum<=length(arg2))
,t3 as (select t1.pos+t2.pos-2 pos,  sum(t1.d*t2.d) p from t1 ,t2 group by t1.pos+t2.pos-2)
,t(r, d, m, str) as(
select 0, 0, 0, cast ('' as varchar2(4000))  from dual
union all
select
r+1,
p,
trunc((m+p)/10),
trunc((m+p)/10) ||mod(m+p,10) || substr(str,2)
from t, t3 where r=pos)
select  * from t where r = (select max(r) from t)

         R          D          M STR
---------- ---------- ---------- --------------------------------------------------------------------------------
        14          8          1 10821155183522114007


Executed in 0.078 seconds


想扩展到多个大数相乘, 还没头绪。

[ 本帖最后由 tree_new_bee 于 2010-12-14 19:30 编辑 ]

使用道具 举报

回复

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

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表